试图定义的问题正好存在于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)

我正在学习Prolog,听说它非常适合解决逻辑难题。我发现了一堆(事实上,用手比用Prolog更容易解决)逻辑难题,比如。重申:

一个邋遢的孩子写了一道乘法题

  • 爱丽丝看到了100 x 6
  • 鲍勃看到了101 x 6
  • 丹看到了102 x 9
  • 每一个都只是误读了数字。这个问题的真正解决办法是什么

    我的第一个想法是定义一个关系,“人在位置上看到数字”:

    那么你可以说一个人,a,如果a在这个位置看到了什么东西,并且没有误读任何其他位置:

    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).