试图定义的问题正好存在于Prolog中
我正在学习Prolog,听说它非常适合解决逻辑难题。我发现了一堆(事实上,用手比用Prolog更容易解决)逻辑难题,比如。重申: 一个邋遢的孩子写了一道乘法题试图定义的问题正好存在于Prolog中,prolog,Prolog,我正在学习Prolog,听说它非常适合解决逻辑难题。我发现了一堆(事实上,用手比用Prolog更容易解决)逻辑难题,比如。重申: 一个邋遢的孩子写了一道乘法题 爱丽丝看到了100 x 6 鲍勃看到了101 x 6 丹看到了102 x 9 每一个都只是误读了数字。这个问题的真正解决办法是什么 我的第一个想法是定义一个关系,“人在位置上看到数字”: 那么你可以说一个人,a,如果a在这个位置看到了什么东西,并且没有误读任何其他位置: saw(alice, 1, 0). saw(alice, 0, 1)
saw(alice, 1, 0).
saw(alice, 0, 1).
saw(alice, 0, 2).
saw(alice, 6, 3).
saw(bob, 1, 0).
saw(bob, 0, 1).
saw(bob, 1, 2).
saw(bob, 6, 3).
saw(dan, 1, 0).
saw(dan, 0, 1).
saw(dan, 2, 2).
saw(dan, 9, 3).
misread(Person, Digit, Position) :-
saw(Person, Digit, Position),
not(misread(Person, _, not(Position))).
那么正确的数字应该是没有误读的数字:
correct(Digit, Position) :-
not(misread(_, Digit, Position)).
因此,可以通过:correct(X,Y)读取解决方案。
然而,我很难理解,我如何才能添加约束,即每个人都误读了一个问题。如对此事有任何提示,将不胜感激
所有代码的组合:
saw(alice, 1, 0).
saw(alice, 0, 1).
saw(alice, 0, 2).
saw(alice, 6, 3).
saw(bob, 1, 0).
saw(bob, 0, 1).
saw(bob, 1, 2).
saw(bob, 6, 3).
saw(dan, 1, 0).
saw(dan, 0, 1).
saw(dan, 2, 2).
saw(dan, 9, 3).
misread(Person, Digit, Position) :-
saw(Person, Digit, Position),
not(misread(Person, _, not(Position))).
correct(Digit, Position) :-
not(misread(_, Digit, Position)).
误读/3非常复杂。具体化,表达其他人读过的内容:
misread(Person, Digit, Position) :-
saw(Person, Digit, Position),
saw(Q, D, Position), Q\==Person, D\==Digit,
saw(R, D, Position), R\==Q, R\==Person.
注:未经测试,我不能说这是否有助于解决这个难题。
但要表达约束,只需遵守目标顺序。失败的否定——我们在纯Prolog中所拥有的——如果没有具体的数据进行比较,就无法工作,然后Q和R上的saw/3
(我们知道我们只有3个实体)为随后的否定提供了信息。实际上,\=
的意思是不是(A==B)
——或者在现代语法中,\+(A==B)
可能尝试将数据流可视化为SQL计划,您正在指示连接顺序
由于搜索空间非常小,因此低效的编码可能会:
misread(Person, Digit, Position) :-
saw(Person, Digit, Position),
saw(Q, D, Position),
saw(R, D, Position),
maplist(\==, [Q,D,R,R],[Person,Digit,Q,Person]).
将所有过滤器放在最后,这将对saw基数执行(糟糕的)O^3
切换到dif/2
将使目标顺序变得无关紧要,并有助于解决性能问题。例如:
misread(Person, Digit, Position) :-
maplist(dif, [Q,D,R,R], [Person,Digit,Q,Person]),
saw(Person, Digit, Position),
saw(Q, D, Position),
saw(R, D, Position).
PS:在看到OP的原始答案后,我取消了这个答案(只是一个提示)。所以我想出了一个问题的答案,现在有了: 重点是:
误读
(与现在删除的答案相关,确保其他人不等同于误读
组件绝对\u误读
,以提高效率(不幸的是,如果没有它,您将得到堆栈错误)不幸的是,这使得它异常冗长,这就是为什么我还问了一个关于CodeReview的问题。我解决这个问题的方法:
saw(alice, 1, 0, 0, 6).
saw(bob, 1, 0, 1, 6).
saw(dan, 1, 0, 2, 9).
首先陈述事实。然后我会对只有一个被误读的事实进行编码:
chk(P, A, B, C, D) :- (saw(P, X, B, C, D), X \= A);
(saw(P, A, X, C, D), X \= B);
(saw(P, A, B, X, D), X \= C);
(saw(P, A, B, C, X), X \= D).
这是..有点硬编码“一是错的”。我相信这是可以改进的。最后解决方案,说明有4个数字,并对其应用上述“检查”:
这个
not(误读(Person,uu,not(Position))
意味着什么?@capelical除非我弄错了:我本打算这样做的:这个人没有误读not(误读(Person,
一个数字,
在任何其他位置not(Position)
。感谢您的帮助,不幸的是,误读
的原因之一很复杂,因为每个人都会犯一个错误。有了明确的限制,位置2永远不会作为解决方案解决,因为它们在这一点上都不同。然而,诀窍是:Dan在所以,他不会在第二位犯错误。
chk(P, A, B, C, D) :- (saw(P, X, B, C, D), X \= A);
(saw(P, A, X, C, D), X \= B);
(saw(P, A, B, X, D), X \= C);
(saw(P, A, B, C, X), X \= D).
digit(A) :- member(A, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).
solve(A,B,C,D) :-
digit(A),
digit(B),
digit(C),
digit(D),
chk(alice, A, B, C, D),
chk(bob, A, B, C, D),
chk(dan, A, B, C, D).