Prolog:如何消除多余的答案?

时间:2014-12-11 08:40:53

标签: prolog prolog-setof

我有 map of Romania来自Russell和Norvig关于人工智能的书。我在城市之间创建了这样的链接:

link(oradea, zerind, 71).
link(oradea, sibiu, 151).
link(zerind, arad, 75).
link(arad, sibiu, 140).
link(arad, timisoara, 118).
link(timisoara, lugoj, 111).
link(lugoj, mehadia, 70).
link(mehadia, drobeta, 75).
link(drobeta, craiova, 120).

我想找到与奥拉迪亚或阿拉德联系的城市,但当我问这个时:

(link(X, arad, _); link(arad, X, _));(link(X, oradea, _); link(oradea, X, _)).

它返回:

X = zerind ;
X = sibiu ;
X = timisoara ;
X = zerind ;
X = sibiu.

如何让它只返回一次解决方案?

3 个答案:

答案 0 :(得分:3)

?- setof(t, Dist^((link(X, arad, Dist) ; link(arad, X, Dist)) ;
                  (link(X, oradea, Dist) ; link(oradea, X, Dist))), _).
X = sibiu ;
X = timisoara ;
X = zerind.

答案 1 :(得分:2)

实现此目标的一种简单方法是使用setof/3,从而消除解决方案列表中的重复项:

?- setof(X, Dist^((link(X, arad, Dist) ; link(arad, X, Dist)) ; 
                  (link(X, oradea, Dist) ; link(orade, X, Dist))), All).

此查询与您的查询之间存在差异,因为在此列表中,所有解决方案都放在列表中,而不是一次一个。但您可以使用member/2来获得相同的行为:

?- setof(X, Dist^((link(X, arad, Dist) ; link(arad, X, Dist)) ;
                  (link(X, oradea, Dist) ; link(oradea, X, Dist))), All),
   member(X, All).
X = sibiu,
All = [sibiu, timisoara, zerind] ;
X = timisoara,
All = [sibiu, timisoara, zerind] ;
X = zerind,
All = [sibiu, timisoara, zerind].

修改:false' answer是一个更好的解决方案,因为它不会构建不必要的列表All

答案 2 :(得分:0)

另一种只获得解决方案的方法是动态使用数据库来存储解决方案:

?- retractall(sol(_)),
   (link(X,arad,_) ; link(arad,X,_) ; link(X,oradea,_) ; link(oradea,X,_)),
   \+ sol(X),
   assertz(sol(X)).

观察:

  1. setof/3的解决方案更好,应该首选。

  2. 为了避免让数据库留下垃圾事实(不良副作用),你可以最后清理它们:

    ?- ( 
         retractall(sol(_)),
         (link(X,arad,_);link(arad, X, _) ; link(X,oradea,_);link(oradea,X,_)),
         \+ sol(X), assertz(sol(X))
       ;
         retractall(sol(_)), fail
       ).