如何用 swi prolog 解决这个难题?
How to solve this puzzle with swiprolog?
我正在尝试使用 prolog 解决这个难题,但我在写下规则和完成解决方案时遇到了困难。
这就是拼图...
上周末举行了一年一度的男子保龄球锦标赛,这是当地市民的一项竞赛和娱乐活动。今年,兴奋 运行 高达五名参赛者并驾齐驱争夺冠军。每次投球手赢得一场比赛,他就得两分,比赛结束时得分最高的投球手获胜。确定每个投球手的全名、他们的最高分(264 到 288)以及每个人赢得多少分(28 到 36)。
F运行k,他姓汤普森,得分最高,但他没有赢得比赛。
先生。史密斯的高分比保龄球手的30分高出3球
史蒂文的姓氏不是斯图尔特。获得36分的锦标赛冠军是单数高分。
迈克尔以比威廉姆斯先生少 6 分的成绩结束了比赛。
273分的高分保龄球手比史密斯先生多两分,但比克雷格少两分。
先生。汤普森获得的积分比沃尔特少,但比史蒂文·刘易斯多。
这就是我目前所拥有的...
first[craig].
first[frank].
first[michael].
first[steven].
first[walter].
last[thompson].
last[williams].
last[smith].
last[lewis].
last[stewart].
high[264].
high[288].
high[276].
high[276].
high[273].
high[285].
points[32].
points[34].
points[28].
points[30].
points[36].'''
'''Sol=[[first(craig),last(Thompson), first(FrankWilliams)]]'''
Please help me
[Logic Diagram picture][1]
[1]: https://i.stack.imgur.com/Wi5lE.png
这是一个相当简单但缓慢的解决方案:
go(Persons):-
length(Persons, 5),
permutation_persons(Persons),
% Clue 1
member(p(frank, FrankSur, FrankScore, 288), Persons),
FrankSur \= thompson,
FrankScore \= 36,
% Clue 2
member(p(_, smith, SmithScore, SmithHigh), Persons),
member(p(_, _, 30, Bowler30High), Persons),
SmithScore \= 30,
SmithHigh is Bowler30High + 3,
% Clue 3a
member(p(steven, StevenSur, _, _), Persons),
StevenSur \= stewart,
% Clue 3b
member(p(_, _, 36, OddHigh), Persons),
1 is OddHigh mod 2,
% Clue 4
member(p(michael, _, MichaelScore, _), Persons),
member(p(_, williams, WilliamsScore, _), Persons),
MichaelScore is WilliamsScore - 6,
% Clue 5
member(p(_, _, Bowler273Score, 273), Persons),
Bowler273Score is SmithScore + 2,
member(p(craig, _, CraigScore, _), Persons),
Bowler273Score is CraigScore - 2,
% Clue 6b
member(p(steven, lewis, StevenScore, _), Persons),
% Clue 6a
member(p(_, thompson, ThompsonScore, _), Persons),
ThompsonScore > StevenScore,
member(p(walter, _, WalterScore, _), Persons),
ThompsonScore < WalterScore.
permutation_persons(Persons) :-
FirstNames = [craig, frank, michael, steven, walter],
Surnames = [thompson, williams, smith, lewis, stewart],
Points = [28, 30, 32, 34, 36],
HighScores = [264, 288, 276, 273, 285],
permute(FirstNames, FP),
permute(Surnames, SP),
permute(HighScores, HP),
assign_persons(Persons, FP, SP, Points, HP).
assign_persons([], _, _, _, _).
assign_persons([H|T], [HF|TF], [HS|TS], [HP|TP], [HH|TH]) :-
H = p(HF, HS, HP, HH),
assign_persons(T, TF, TS, TP, TH).
% Fast permutation (rearrangement)
permute([], []).
permute([X|Rest], L) :-
permute(Rest, L1),
select(X, L, L1).
结果swi-prolog:
?- time(findall(P, go(P), Ps)).
% 27,505,015 inferences, 3.287 CPU in 3.247 seconds (101% CPU, 8367859 Lips)
Ps = [[p(michael,smith,28,276),p(steven,lewis,30,273),p(craig,thompson,32,264),p(frank,williams,34,288),p(walter,stewart,36,285)]].
我花了很长时间想知道为什么它没有解决一个单一的解决方案,没有看链接的图片或你的代码,也没有意识到所有的高分都有给定的值。 :-|
您的代码 last[thompson].
可能应该是 last(thompson).
来表示“thompson 是一个姓氏”,但是如果不构建所有有效姓氏的列表,就很难从中得到任何有用的信息.从那里您也可以将有效的姓氏放入列表中。
我选择了一个复合词 bowler(Firstname, Lastname, Highscore, Points)
作为我想看到的输出,所以我制作了一个 Bowlers
的列表,其中有五个。然后添加线索信息以解决 brute-force 搜索样式中的值,其工作方式如下:
% Mr. Smith’s high score was three pins higher than that of the bowler with 30 points.
member(bowler(_, smith, Hsmith, _), Bowlers),
member(bowler(_, _, H_30, 30), Bowlers),
Hsmith is H_30 + 3,
说“只有当保龄球队中有一名成员的姓氏与史密斯相匹配,史密斯的一些高分,以及另一名成员的得分为 30 分时,才能找到解决方案,这两个得分变量相差 3 分”。全文:
:- use_module(library(dif)).
solve(Bowlers) :-
% bowler(Firstname, Lastname, Highscore, Points).
Bowlers = [ bowler(frank, L1, H1, P1),
bowler(michael, L2, H2, P2),
bowler(steven, L3, H3, P3),
bowler(craig, L4, H4, P4),
bowler(walter, L5, H5, P5) ],
% everyone has last names from the text
permutation([L1, L2, L3, L4, L5], [smith, stewart, williams, thompson, lewis]),
% apparently the scores are evenly distributed one per person, no dupes.
permutation([P1, P2, P3, P4, P5], [28, 30, 32, 34, 36]),
% the valid high scores, one per person, no dupes.
permutation([H1, H2, H3, H4, H5], [264, 288, 276, 273, 285]),
% Frank, whose last name wasn’t Thompson,
% had the highest score (288) but he didn’t win the tournament (didn't score 36 points).
member(bowler(frank, Lfrank, 288, Pfrank), Bowlers),
dif(Lfrank, thompson),
dif(Pfrank, 36),
% Mr. Smith’s high score was three pins higher than that of the bowler with 30 points.
member(bowler(_, smith, Hsmith, _), Bowlers),
member(bowler(_, _, H_30, 30), Bowlers),
Hsmith is H_30 + 3,
% Steven’s last name wasn’t Stewart
member(bowler(steven, Ssteven, _, _), Bowlers),
dif(Ssteven, stewart),
% The winner of the tournament, who had 36 points, had an odd number for a high score.
member(bowler(_, _, Hwin, 36), Bowlers),
1 is Hwin /\ 1,
% Michael finished the tournament with six points less than Mr. Williams.
member(bowler(michael, _, _, Pmichael), Bowlers),
member(bowler(_, williams, _, Pwilliams), Bowlers),
Pmichael is Pwilliams - 6,
% The bowler with a high score of 273 had two points more than Mr. Smith but two points less than Craig.
member(bowler(_, _, 273, P_273), Bowlers),
member(bowler(_, smith, _, Psmith), Bowlers),
member(bowler(craig, _, _, Pcraig), Bowlers),
P_273 is Psmith + 2,
P_273 is Pcraig - 2,
% Mr. Thompson won fewer points than Walter but more than Steven Lewis.
member(bowler(_, thompson, _, Pthompson), Bowlers),
member(bowler(walter, _, _, Pwalter), Bowlers),
member(bowler(steven, lewis, _, Plewis), Bowlers),
Pthompson < Pwalter,
Pthompson > Plewis.
这感觉很慢,要解决 1000 万个推论,还有 1700 万个要排除任何其他解决方案:
?- time(solve(B)).
10,099,024 inferences, 1.550 CPU in 1.550 seconds (100% CPU, 6517307 Lips)
B = [bowler(frank, williams, 288, 34), bowler(michael, smith, 276, 28), bowler(steven, lewis, 273, 30), bowler(craig, thompson, 264, 32), bowler(walter, stewart, 285, 36)]
1.550 seconds cpu time
17,191,884 inferences, 2.613 CPU in 2.613 seconds (100% CPU, 6579160 Lips)
false
它从代码的顶部向下搜索,生成一个名字的排列,一个点,一个分数,然后检查 frank
没有得到 thompson
作为他的姓氏,回溯和再次尝试,直到它生成一个通过所有检查的解决方案。
通过重新排序子句以更快地失败,从而在失败之前做更少的工作,并从文本中添加更多提示,可以减少工作量。例如从最后一条线索我们知道一个成员肯定是Steven Smith,我们知道Frank的分数是288,我们可以直接写“Mr Smiths score is 3 pin higher than...”,得到这个版本:
:- use_module(library(dif)).
solve(Bowlers) :-
% bowler(Firstname, Lastname, Highscore, Points).
Bowlers = [ bowler(frank, L1, 288, P1),
bowler(michael, L2, H2, P2),
bowler(steven, lewis, H3, P3),
bowler(craig, L4, H4, P4),
bowler(walter, L5, H5, P5) ],
dif(L1, thompson), % Frank, whose last name wasn’t Thompson
dif(P1, 36), % didn’t win (didn't score 36 points).
dif(L5, thompson), % Walter isn't Mr Thompson because they scored differently.
dif(L4, smith), % Craig isn't Mr Smith because they scored differently.
dif(L2, williams), % Michael isn't Mr Williams because they scored differently.
% everyone has last names from the text
permutation([L1, L2, L4, L5], [smith, stewart, williams, thompson]),
% scores are evenly distributed one per person, no dupes.
permutation([P1, P2, P3, P4, P5], [28, 30, 32, 34, 36]),
% Michael finished the tournament with six points less than Mr. Williams.
member(bowler(_, williams, _, Pwilliams), Bowlers),
P2 is Pwilliams - 6,
% the valid high scores, one per person, no dupes.
permutation([H2, H3, H4, H5], [264, 276, 273, 285]),
% The winner of the tournament, who had 36 points, had an odd number for a high score.
member(bowler(_, _, Hwin, 36), Bowlers),
1 is rem(Hwin, 2),
% Mr. Smith’s high score was three pins higher than that of the bowler with 30 points.
member(bowler(_, _, H_30, 30), Bowlers),
Hsmith is H_30 + 3,
member(bowler(_, smith, Hsmith, Psmith), Bowlers),
% The bowler with a high score of 273 had two points more than Mr. Smith but two points less than Craig.
P_273 is Psmith + 2,
member(bowler(_, _, 273, P_273), Bowlers),
Pcraig is P_273 + 2,
member(bowler(craig, _, _, Pcraig), Bowlers),
% Mr. Thompson won fewer points than Walter but more than Steven Lewis.
member(bowler(_, thompson, _, Pthompson), Bowlers),
member(bowler(walter, _, _, Pwalter), Bowlers),
Pthompson < Pwalter,
member(bowler(steven, lewis, _, Plewis), Bowlers),
Pthompson > Plewis.
此版本:
?- time(solve(B)).
34,664 inferences, 0.007 CPU in 0.007 seconds (100% CPU, 5150062 Lips)
B = [bowler(frank, williams, 288, 34), bowler(michael, smith, 276, 28), bowler(steven, lewis, 273, 30), bowler(craig, thompson, 264, 32), bowler(walter, stewart, 285, 36)]
26,321 inferences, 0.011 CPU in 0.011 seconds (100% CPU, 2397565 Lips)
false
几乎快了 300 倍。
我正在尝试使用 prolog 解决这个难题,但我在写下规则和完成解决方案时遇到了困难。 这就是拼图...
上周末举行了一年一度的男子保龄球锦标赛,这是当地市民的一项竞赛和娱乐活动。今年,兴奋 运行 高达五名参赛者并驾齐驱争夺冠军。每次投球手赢得一场比赛,他就得两分,比赛结束时得分最高的投球手获胜。确定每个投球手的全名、他们的最高分(264 到 288)以及每个人赢得多少分(28 到 36)。
F运行k,他姓汤普森,得分最高,但他没有赢得比赛。
先生。史密斯的高分比保龄球手的30分高出3球
史蒂文的姓氏不是斯图尔特。获得36分的锦标赛冠军是单数高分。
迈克尔以比威廉姆斯先生少 6 分的成绩结束了比赛。
273分的高分保龄球手比史密斯先生多两分,但比克雷格少两分。
先生。汤普森获得的积分比沃尔特少,但比史蒂文·刘易斯多。
这就是我目前所拥有的...
first[craig].
first[frank].
first[michael].
first[steven].
first[walter].
last[thompson].
last[williams].
last[smith].
last[lewis].
last[stewart].
high[264].
high[288].
high[276].
high[276].
high[273].
high[285].
points[32].
points[34].
points[28].
points[30].
points[36].'''
'''Sol=[[first(craig),last(Thompson), first(FrankWilliams)]]'''
Please help me
[Logic Diagram picture][1]
[1]: https://i.stack.imgur.com/Wi5lE.png
这是一个相当简单但缓慢的解决方案:
go(Persons):-
length(Persons, 5),
permutation_persons(Persons),
% Clue 1
member(p(frank, FrankSur, FrankScore, 288), Persons),
FrankSur \= thompson,
FrankScore \= 36,
% Clue 2
member(p(_, smith, SmithScore, SmithHigh), Persons),
member(p(_, _, 30, Bowler30High), Persons),
SmithScore \= 30,
SmithHigh is Bowler30High + 3,
% Clue 3a
member(p(steven, StevenSur, _, _), Persons),
StevenSur \= stewart,
% Clue 3b
member(p(_, _, 36, OddHigh), Persons),
1 is OddHigh mod 2,
% Clue 4
member(p(michael, _, MichaelScore, _), Persons),
member(p(_, williams, WilliamsScore, _), Persons),
MichaelScore is WilliamsScore - 6,
% Clue 5
member(p(_, _, Bowler273Score, 273), Persons),
Bowler273Score is SmithScore + 2,
member(p(craig, _, CraigScore, _), Persons),
Bowler273Score is CraigScore - 2,
% Clue 6b
member(p(steven, lewis, StevenScore, _), Persons),
% Clue 6a
member(p(_, thompson, ThompsonScore, _), Persons),
ThompsonScore > StevenScore,
member(p(walter, _, WalterScore, _), Persons),
ThompsonScore < WalterScore.
permutation_persons(Persons) :-
FirstNames = [craig, frank, michael, steven, walter],
Surnames = [thompson, williams, smith, lewis, stewart],
Points = [28, 30, 32, 34, 36],
HighScores = [264, 288, 276, 273, 285],
permute(FirstNames, FP),
permute(Surnames, SP),
permute(HighScores, HP),
assign_persons(Persons, FP, SP, Points, HP).
assign_persons([], _, _, _, _).
assign_persons([H|T], [HF|TF], [HS|TS], [HP|TP], [HH|TH]) :-
H = p(HF, HS, HP, HH),
assign_persons(T, TF, TS, TP, TH).
% Fast permutation (rearrangement)
permute([], []).
permute([X|Rest], L) :-
permute(Rest, L1),
select(X, L, L1).
结果swi-prolog:
?- time(findall(P, go(P), Ps)).
% 27,505,015 inferences, 3.287 CPU in 3.247 seconds (101% CPU, 8367859 Lips)
Ps = [[p(michael,smith,28,276),p(steven,lewis,30,273),p(craig,thompson,32,264),p(frank,williams,34,288),p(walter,stewart,36,285)]].
我花了很长时间想知道为什么它没有解决一个单一的解决方案,没有看链接的图片或你的代码,也没有意识到所有的高分都有给定的值。 :-|
您的代码 last[thompson].
可能应该是 last(thompson).
来表示“thompson 是一个姓氏”,但是如果不构建所有有效姓氏的列表,就很难从中得到任何有用的信息.从那里您也可以将有效的姓氏放入列表中。
我选择了一个复合词 bowler(Firstname, Lastname, Highscore, Points)
作为我想看到的输出,所以我制作了一个 Bowlers
的列表,其中有五个。然后添加线索信息以解决 brute-force 搜索样式中的值,其工作方式如下:
% Mr. Smith’s high score was three pins higher than that of the bowler with 30 points.
member(bowler(_, smith, Hsmith, _), Bowlers),
member(bowler(_, _, H_30, 30), Bowlers),
Hsmith is H_30 + 3,
说“只有当保龄球队中有一名成员的姓氏与史密斯相匹配,史密斯的一些高分,以及另一名成员的得分为 30 分时,才能找到解决方案,这两个得分变量相差 3 分”。全文:
:- use_module(library(dif)).
solve(Bowlers) :-
% bowler(Firstname, Lastname, Highscore, Points).
Bowlers = [ bowler(frank, L1, H1, P1),
bowler(michael, L2, H2, P2),
bowler(steven, L3, H3, P3),
bowler(craig, L4, H4, P4),
bowler(walter, L5, H5, P5) ],
% everyone has last names from the text
permutation([L1, L2, L3, L4, L5], [smith, stewart, williams, thompson, lewis]),
% apparently the scores are evenly distributed one per person, no dupes.
permutation([P1, P2, P3, P4, P5], [28, 30, 32, 34, 36]),
% the valid high scores, one per person, no dupes.
permutation([H1, H2, H3, H4, H5], [264, 288, 276, 273, 285]),
% Frank, whose last name wasn’t Thompson,
% had the highest score (288) but he didn’t win the tournament (didn't score 36 points).
member(bowler(frank, Lfrank, 288, Pfrank), Bowlers),
dif(Lfrank, thompson),
dif(Pfrank, 36),
% Mr. Smith’s high score was three pins higher than that of the bowler with 30 points.
member(bowler(_, smith, Hsmith, _), Bowlers),
member(bowler(_, _, H_30, 30), Bowlers),
Hsmith is H_30 + 3,
% Steven’s last name wasn’t Stewart
member(bowler(steven, Ssteven, _, _), Bowlers),
dif(Ssteven, stewart),
% The winner of the tournament, who had 36 points, had an odd number for a high score.
member(bowler(_, _, Hwin, 36), Bowlers),
1 is Hwin /\ 1,
% Michael finished the tournament with six points less than Mr. Williams.
member(bowler(michael, _, _, Pmichael), Bowlers),
member(bowler(_, williams, _, Pwilliams), Bowlers),
Pmichael is Pwilliams - 6,
% The bowler with a high score of 273 had two points more than Mr. Smith but two points less than Craig.
member(bowler(_, _, 273, P_273), Bowlers),
member(bowler(_, smith, _, Psmith), Bowlers),
member(bowler(craig, _, _, Pcraig), Bowlers),
P_273 is Psmith + 2,
P_273 is Pcraig - 2,
% Mr. Thompson won fewer points than Walter but more than Steven Lewis.
member(bowler(_, thompson, _, Pthompson), Bowlers),
member(bowler(walter, _, _, Pwalter), Bowlers),
member(bowler(steven, lewis, _, Plewis), Bowlers),
Pthompson < Pwalter,
Pthompson > Plewis.
这感觉很慢,要解决 1000 万个推论,还有 1700 万个要排除任何其他解决方案:
?- time(solve(B)).
10,099,024 inferences, 1.550 CPU in 1.550 seconds (100% CPU, 6517307 Lips)
B = [bowler(frank, williams, 288, 34), bowler(michael, smith, 276, 28), bowler(steven, lewis, 273, 30), bowler(craig, thompson, 264, 32), bowler(walter, stewart, 285, 36)]
1.550 seconds cpu time
17,191,884 inferences, 2.613 CPU in 2.613 seconds (100% CPU, 6579160 Lips)
false
它从代码的顶部向下搜索,生成一个名字的排列,一个点,一个分数,然后检查 frank
没有得到 thompson
作为他的姓氏,回溯和再次尝试,直到它生成一个通过所有检查的解决方案。
通过重新排序子句以更快地失败,从而在失败之前做更少的工作,并从文本中添加更多提示,可以减少工作量。例如从最后一条线索我们知道一个成员肯定是Steven Smith,我们知道Frank的分数是288,我们可以直接写“Mr Smiths score is 3 pin higher than...”,得到这个版本:
:- use_module(library(dif)).
solve(Bowlers) :-
% bowler(Firstname, Lastname, Highscore, Points).
Bowlers = [ bowler(frank, L1, 288, P1),
bowler(michael, L2, H2, P2),
bowler(steven, lewis, H3, P3),
bowler(craig, L4, H4, P4),
bowler(walter, L5, H5, P5) ],
dif(L1, thompson), % Frank, whose last name wasn’t Thompson
dif(P1, 36), % didn’t win (didn't score 36 points).
dif(L5, thompson), % Walter isn't Mr Thompson because they scored differently.
dif(L4, smith), % Craig isn't Mr Smith because they scored differently.
dif(L2, williams), % Michael isn't Mr Williams because they scored differently.
% everyone has last names from the text
permutation([L1, L2, L4, L5], [smith, stewart, williams, thompson]),
% scores are evenly distributed one per person, no dupes.
permutation([P1, P2, P3, P4, P5], [28, 30, 32, 34, 36]),
% Michael finished the tournament with six points less than Mr. Williams.
member(bowler(_, williams, _, Pwilliams), Bowlers),
P2 is Pwilliams - 6,
% the valid high scores, one per person, no dupes.
permutation([H2, H3, H4, H5], [264, 276, 273, 285]),
% The winner of the tournament, who had 36 points, had an odd number for a high score.
member(bowler(_, _, Hwin, 36), Bowlers),
1 is rem(Hwin, 2),
% Mr. Smith’s high score was three pins higher than that of the bowler with 30 points.
member(bowler(_, _, H_30, 30), Bowlers),
Hsmith is H_30 + 3,
member(bowler(_, smith, Hsmith, Psmith), Bowlers),
% The bowler with a high score of 273 had two points more than Mr. Smith but two points less than Craig.
P_273 is Psmith + 2,
member(bowler(_, _, 273, P_273), Bowlers),
Pcraig is P_273 + 2,
member(bowler(craig, _, _, Pcraig), Bowlers),
% Mr. Thompson won fewer points than Walter but more than Steven Lewis.
member(bowler(_, thompson, _, Pthompson), Bowlers),
member(bowler(walter, _, _, Pwalter), Bowlers),
Pthompson < Pwalter,
member(bowler(steven, lewis, _, Plewis), Bowlers),
Pthompson > Plewis.
此版本:
?- time(solve(B)).
34,664 inferences, 0.007 CPU in 0.007 seconds (100% CPU, 5150062 Lips)
B = [bowler(frank, williams, 288, 34), bowler(michael, smith, 276, 28), bowler(steven, lewis, 273, 30), bowler(craig, thompson, 264, 32), bowler(walter, stewart, 285, 36)]
26,321 inferences, 0.011 CPU in 0.011 seconds (100% CPU, 2397565 Lips)
false
几乎快了 300 倍。