在Prolog中,大部分時間減輕事情的做法是使用累加器。累加器是您遞歸傳遞並在每個遞歸步驟中更新的變量。每個遞歸步驟都可以檢查變量的值並據此作出決定。這裏的累加器就是這個項目的價格總和這個遠加到S
。顯然,在一開始,即總和爲零,所以我們首先通過引入蓄電池緩解事情有點:
basket(L,Smin,Smax,S) :-
basket(L,Smin,Smax,0,S).
現在,我們需要制定出basket/5
。有一個基礎案例,其中列舉了所有項目。因此L
爲空。我們需要做的是什麼,是檢查是否Sum
是指定的界限之間:
basket([],Smin,Smax,Sum,[]) :-
Smin < S,
S < Smax.
這是唯一的基本情況。請注意,S
(最後一個參數)也是空列表。由於所有項目都已經過檢查,這意味着我們不會將任何元素添加到子集的尾部。
現在有兩個遞歸情況。在遞歸的情況下,L
包含至少一個元素,我們可以做兩件事情:
- 我們要麼接受這個項目,並將其添加到我們的子集;
- 或我們丟棄該物品,並繼續進一步操作。
在我們接受這個項目的情況下,謂詞的樣子:
basket([(I,V)|T],Smin,Smax,Sum,[(I,V)|S]) :-
Sum1 is Sum+V,
Sum1 < Smax,
basket(T,Smin,Smax,Sum1,S).
因此,我們決定要添加的元素,我們通過添加值V
原來的Sum
計算新的總和Sum1
,我們可以(可選)已經對值的上限執行邊界檢查。如果存在大量物品,這可以是有效的:我們的包從溢出時開始運行的那一刻起就停止了搜索。
最後,我們有另一個遞歸的情況下,我們只是決定放棄該項目。這是一個簡單的一個:
basket([_|T],Smin,Smax,Sum,S) :-
basket(T,Smin,Smax,Sum,S).
我們甚至不看頭,我們簡單地採取feeded到basket
列表的尾部,我們沒有更新Sum
,因爲沒有任何改變的子集。
全部放在一起,下面的程序應該做的伎倆:
basket(L,Smin,Smax,S) :-
basket(L,Smin,Smax,0,S).
basket([],Smin,Smax,Sum,[]) :-
Smin < S,
S < Smax.
basket([(I,V)|T],Smin,Smax,Sum,[(I,V)|S]) :-
Sum1 is Sum+V,
Sum1 < Smax,
basket(T,Smin,Smax,Sum1,S).
basket([_|T],Smin,Smax,Sum,S) :-
basket(T,Smin,Smax,Sum,S).
不過請注意,使用動態編程一個可以更有效地生成解決方案的方式。
這是功課?你有什麼嘗試? –
請顯示您嘗試過的內容。 – lurker
你好。關於[如何問作業問題]的文檔(http://meta.stackexchange.com/questions/10811/how-do-i-ask-and-answer-homework-questions)說:「做一個誠信的嘗試如果我們看不到你方面有足夠的工作,你的問題很可能會被拋出舞臺,它會被拒絕並被關閉。「請張貼代碼。 –