1

有一个合乎逻辑的问题:四个朋友:伊万、彼得、米哈伊尔、谢尔盖以不同的方式度过他们的时间:两个下棋,一个看书,一个看电视。如果 Sergey 不下棋而 Petr 不看电视,找出谁会做什么。

这是我的解决方案:

PREDICATES
    question(string,string,string,string)
    friend(string)
    readBook(string)
    watchTV(string)
    playsChess(string, string)

CLAUSES
    friend(ivan).
    friend(petr).
    friend(mikhail).
    friend(sergey).

    readBook(X):-
        friend(X).

    watchTV(X):-
        friend(X),
        X<>"petr".

    playsChess(X,Y):-
        friend(X),
        friend(Y),
        X<>Y,
        X<>"sergey",
        Y<>"sergey".

    question(A,B,C,D):-
        friend(A),
        friend(B),
        friend(C),
        friend(D),
        playsChess(A,B),
        readBook(C),
        watchTV(D),
        A<>B, A<>C, A<>D,
        B<>C, B<>D,
        C<>D.
GOAL
    question(A,B,C,D).

我有以下解决方案:

A=ivan, B=petr, C=mikhail, D=sergey (1)
A=ivan, B=petr, C=sergey, D=mikhail (2)
A=ivan, B=mikhail, C=petr, D=sergey (3)
A=petr, B=ivan, C=mikhail, D=sergey (4)
A=petr, B=ivan, C=sergey, D=mikhail (5)
A=petr, B=mikhail, C=ivan, D=sergey (6)
A=petr, B=mikhail, C=sergey, D=ivan (7)
A=mikhail, B=ivan, C=petr, D=sergey (8)
A=mikhail, B=petr, C=ivan, D=sergey (9)
A=mikhail, B=petr, C=sergey, D=ivan (10)
10 Solutions

但是有些行是多余的,因为它们是 A 和 B 的组合。例如行 (1) 和 (4) (A=ivan, B=petr and A=petr, B=ivan)。我尝试在!这里使用:

playsChess(X,Y):-!,
    friend(X),
    friend(Y),
    X<>Y,
    X<>"sergey",
    Y<>"sergey".

但它没有效果。所以问题是:我怎样才能摆脱多余的解决方案结果?

4

2 回答 2

3

考虑使用您为每个朋友介绍的变量来直接表示该人对应的活动:

friends([ivan=Ivan,petr=Petr,mikhail=Mikhail,sergey=Sergey]) :-
        Fs0 = [Ivan,Petr,Mikhail,Sergey],
        dif(Sergey, chess),
        dif(Petr, tv),
        select(books, Fs0, Fs1),
        select(tv, Fs1, [chess,chess]).

示例查询及其结果:

?- friends(Fs).
Fs = [ivan=books, petr=chess, mikhail=chess, sergey=tv] ;
Fs = [ivan=chess, petr=books, mikhail=chess, sergey=tv] ;
Fs = [ivan=chess, petr=chess, mikhail=books, sergey=tv] ;
Fs = [ivan=tv, petr=chess, mikhail=chess, sergey=books] ;
Fs = [ivan=chess, petr=chess, mikhail=tv, sergey=books] ;
false.
于 2015-02-25T20:20:23.073 回答
2

解决问题的最简单方法是限制AB进一步迫使一个人比另一个人“更大”。我不确定这是否是 Visual Prolog 中的语法,但试试这个。注意使用A > B代替A <> B

question(A,B,C,D):-
    friend(A),
    friend(B),
    friend(C),
    friend(D),
    playsChess(A,B),
    readBook(C),
    watchTV(D),
    A > B, A<>C, A<>D,
    B<>C, B<>D,
    C<>D.

通过约束 with>而不是<>you 将确保您不会有对称的情况。例如,a > b为假,但a < b为真。然而,两者a <> bb <> a都是真的,所以<>给出a, bb, a

你的 cut ( !) 什么也没做,因为当你在一个只有这样一个子句的谓词上使用它时:

my_predicate(...) :- !, subqueries ...

它只是告诉 Prolog 不要回溯到第一个子查询的开头。由于my_predicate无论如何都没有其他子句可以回溯,所以它没有效果。

于 2015-02-25T20:20:15.117 回答