養的不同的寵物,喜歡和不同的飲料,抽不同牌子的煙。現在已知以下的壹些信息
英國人(englishman)住在紅色(red)的房子裏。
西班牙人(spaniard)養了壹條狗(dog)。
挪威人(norwegian)住在左邊的第壹個房子裏。
黃房子(yellow)裏的人喜歡抽kools牌的香煙。
抽chesterfields牌香煙的人與養狐貍(fox)的人是鄰居。
挪威人(norwegian)住在藍色(blue)的房子旁邊。
抽winston牌香煙的人養了壹只蝸牛(Snails)。
抽Lucky Strike牌香煙的人喜歡喝桔子汁(orange juice)。
烏克蘭人(ukrainian)喜歡喝茶(tea)。
日本人(japanese)抽parliaments牌的煙。
抽kools牌的香煙的人與養馬(horse)的人是鄰居。
喜歡喝咖啡(coffee)的人住在綠(green)房子裏。
綠(green)房子在象牙白(ivory)房子的右邊(圖中的右邊)。
中間那個房子裏的人喜歡喝牛奶(milk)。
根據以上條件,妳能告訴我哪個房子裏的人養斑馬(zebra),哪個房子裏的人喜
歡喝水(water)嗎?或者妳能把所有的東西都對號入座嗎?
這是個典型的條件約束的問題,根據每個條件,我們都可以排除壹些情況,直到最
後找到答案。不過由於這個問題的條件太多,如果人工來解答,是很要花上壹點時
間的。還不如我們用這個時間來編壹個程序,讓計算機來解答。真的,編程花的時
間壹定要比人工計算還要少!
使用Prolog來解決這類的問題,壹般使用的是“選擇再校驗”的方法。即用某種方
法提出壹系列的可能的解,再由校驗部分來判斷此解是否合乎題意。直到找到答案
為止。
我們先來分析壹下到底有多少種可能的解。
每個房子有不同的顏色,所以就顏色來說就有5!種情況,而壹***有五個特征:顏
色、國籍、寵物、香煙和飲料。所以壹***就有5!*5種情況,即600種。不是很多,
完全可以使用程序窮舉出來。
下面介紹如何使用Prolog來編寫解答的程序。
在此程序中使用結構h(C,N,P,Y,D)來儲存房間的信息。C,N,P,Y,D分別對應顏色、
國籍、寵物、香煙和飲料。由於有五個房間,所以使用列表來儲存所有房間的信息
。此列表為:
[h(C1,N1,P1,Y1,D1),h(C2,N2,P2,Y2,D2),h(C3,N3,P3,Y3,D3),h(C4,N4,P4,Y4,
D4),h(C5,N5,P5,Y5,D5)]
壹開始所有房間的情況都是未知的,所以就使用變量來代表每個房間的情況。
在後面的條件中經常要讀取房間的某個信息,所以下面就先編寫五個謂詞來完成這
項工作。
color(h(C,N,P,Y,D),C).
nation(h(C,N,P,Y,D),N).
pet(h(C,N,P,Y,D),P).
yan(h(C,N,P,Y,D),Y).
drink(h(C,N,P,Y,D),D).
這幾個謂詞很容易理解,所以就不多作解釋了。
在條件中還用到了房間之間的相對位置的信息,下面的謂詞就是完成這個任務的。
next(A,B,[A,B,C,D,E]).
next(B,C,[A,B,C,D,E]).
next(C,D,[A,B,C,D,E]).
next(D,E,[A,B,C,D,E]).
next(B,A,[A,B,C,D,E]).
next(C,B,[A,B,C,D,E]).
next(D,C,[A,B,C,D,E]).
next(E,D,[A,B,C,D,E]).
middle(X,[_,_,X,_,_]).
first(A,[A|X]).
上面,next/3用來判斷列表中兩個元素是否相鄰;middle/2用來讀取列表的中間的
元素;first/2讀取列表的第壹個元素。當然,next/3不但可以判斷相鄰,它還能
找出相鄰的元素來。例如:
- next(4,X,[1,2,3,4,5]).X = 5 ;
X = 3 ;
no
很明顯,next找出了列表[1,2,3,4,5]中與4相鄰的元素。這裏列表的元素是簡單的
數字,如果是上面說所的表示房間信息的結構h(C,N,P,Y,D),它的功能也是相同的
前面說過,我們將使用“選擇再校驗”的方法找出答案,那麽我們靠什麽來選擇呢
?這裏將使用以前介紹過的member/2謂詞。還記得member/2的定義麽?
member(A,[A|X]).
member(A,[B|X]) :- member(A,X).
它的第二個參數是壹個列表,它可以判斷第壹個參數是否在這個列表中。我們是使
用遞歸的方法編寫member/2的,如果不太清楚,請閱讀列表這壹章。
- member(2,[1,2,3]).yes
我們曾經說過Prolog的謂詞有多種使用方法,所以member/2還可以用來遍歷列表的
所有元素。
-member(X,[1,2,3,4,5]).X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
no
這正是我們需要的功能,使用它就可以選擇出所有的情況了。
有了以上的準備工作,我們就可以開始正式編寫解答部分了。我們先把程序列出來
,然後再來講解。解題的謂詞為solve/3,第壹個參數X返回所以東西對號入座後的
房間列表,第二參數TT返回養斑馬的人住的房間,第三個參數TTT返回喜歡喝水的
人的房間。
solve(X,TT,TTT):-
%首先把X綁定為房間列表,註意此時的房間的屬性還不能確定,所以都使用變量
代表。
X=[h(C1,N1,P1,Y1,D1),h(C2,N2,P2,Y2,D2),h(C3,N3,P3,Y3,D3),h(C4,N4,P4,
Y4,D4),h(C5,N5,P5,Y5,D5)],
%英國人(englishman)住在紅色(red)的房子裏。
member(Z1,X), %首先從X列表中選擇壹個房間Z1,
color(Z1,red), %Z1的顏色是red。
nation(Z1,englishman), %Z1裏住的人是englishman。 下同。
%西班牙人(spaniard)養了壹條狗(dog)。
member(Z2,X),
pet(Z2,dog),
nation(Z2,spaniard),
%挪威人(norwegian)住在左邊的第壹個房子裏。
first(Z3,X),
nation(Z3,norwegian),
%黃房子(yellow)裏的人喜歡抽kools牌的香煙。
member(Z4,X),
yan(Z4,kools),
color(Z4,yellow),
%抽chesterfields牌香煙的人與養狐貍(fox)的人是鄰居。
member(Z5,X),
pet(Z5,fox),
next(Z6,Z5,X), %用next(Z5,Z6,X)也壹樣。
yan(Z6,chesterfields),
%挪威人(norwegian)住在藍色(blue)的房子旁邊。
member(Z7,X),
color(Z7,blue),
next(Z8,Z7,X),
nation(Z8,norwegian),
%抽winston牌香煙的人養了壹只蝸牛(Snails)。
member(Z9,X),
yan(Z9,winston),
pet(Z9,snails),
%抽Lucky Strike牌香煙的人喜歡喝桔子汁(orange juice)。
member(Z10,X),
drink(Z10,'orange juice'),
yan(Z10,'Lucky Strike'),
%烏克蘭人(ukrainian)喜歡喝茶(tea)。
member(Z11,X),
nation(Z11,ukrainian),
drink(Z11,tea),
%日本人(japanese)抽parliaments牌的煙。
member(Z12,X),
nation(Z12,japanese),
yan(Z12,parliaments),
%抽kools牌的香煙的人與養馬(horse)的人是鄰居。
member(Z13,X),
pet(Z13,horse),
next(Z14,Z13,X),
yan(Z14,kools),
%喜歡喝咖啡(coffee)的人住在綠(green)房子裏。
member(Z15,X),
color(Z15,green),
drink(Z15,coffee),
%綠(green)房子在象牙白(ivory)房子的右邊(圖中的右邊)。
member(Z16,X),
color(Z16,ivory),
next(Z17,Z16,X), %這裏我們沒有使用右邊的條件,而是假設它們是鄰居,所
以最後的答案有兩個。
color(Z17,green), %這壹點請讀者自己修改,當然還需要編寫壹個判斷右邊的
謂詞。
%中間那個房子裏的人喜歡喝牛奶(milk)。
middle(Z18,X),
drink(Z18,milk),
%以上是所有的條件,下面開始回答我們的問題。
%找出寵物為zebra的房間。
member(TT,X),
pet(TT,zebra),
%找出喝水的房間。
member(TTT,X),
drink(TTT,water).
妳閱讀這個程序應該沒有什麽問題吧。它簡直就是把我們的條件直接翻譯成
Prolog語言。例如:
%抽chesterfields牌香煙的人與養狐貍(fox)的人是鄰居。
member(Z5,X),
pet(Z5,fox),
next(Z6,Z5,X), %用next(Z5,Z6,X)也壹樣。
yan(Z6,chesterfields),
用語言來描述就是:首先Z5是個房子,對應於member(Z5,X);然後它的寵物是fox
,對應於pet(Z5,fox);它的鄰居是Z6,對應於next(Z6,Z5,X);最後Z6的人抽
chesterfields,對應於yan(Z6,chesterfields)。妳看只要把原始的條件稍加分解
,就變成了我們的Prolog程序。
哈哈,這樣的程序誰都可以編出來,妳看到Prolog的優勢了吧。Prolog是描述型的
語言,妳只要使用Prolog的語言把問題描述壹遍就行了,剩下的問題就讓計算機代
勞吧:)。如果使用其它的語言,例如C、Basic等,妳就不得不自己考慮程序的流程
,所以這些語言都叫作過程型的語言。比起Prolog可是低級多了。
好了,最後讓我們來運行壹下程序。
- solve(X,TT,TTT).X = [h(yellow,norwegian,fox,kools,water),h(blue,ukrainian,horse,
chesterfields,tea),
h(red,englishman,snails,winston,milk),h(iory,spaniard,dog,'Lucky
Strike','orange juice'),
h(green,japanese,zebra,parliaments,coffee)]
TT = h(green,japanese,zebra,parliaments,coffee)
TTT = h(yellow,norwegian,fox,kools,water) ;
X = [h(yellow,norwegian,fox,kools,water),h(blue,ukrainian,horse,
chesterfields,tea),
h(red,englishman,snails,winston,milk),h(green,japanese,zebra,
parliaments,coffee),
h(ivory,spaniard,dog,'Lucky Strike','orange juice')]
TT = h(green,japanese,zebra,parliaments,coffee)
TTT = h(yellow,norwegian,fox,kools,water)
no
由於第13個條件中我們沒有使用題目中的右邊的限制,所以答案就有兩個,妳可以
看到這兩個答案的最後兩個房間正好倒了過來。
再花點功夫把答案更美觀地寫出來,這個程序就完美了。