2015-07-03 72 views
4

这就是问题简而言之: 16个孩子要坐在4 x 4阵列椅子上。这些孩子是8个女孩(编号1..8)和8个男孩(编号9..16)。 1,3,5,8认为男孩是堕胎 9,10,11,14认为女孩是毛 这些对是敌人: [[1,2],[4,6],[4,7], [4,9],[9,11],[12,14],[14,16]]排除序言中的tuples_in列表

找到两个孩子不是敌人谓词被定义为:

not_enemy(A, B) :- 
    NotA #\= A #\/ NotB #\= B, 
    tuples_in([[NotA, NotB]], 
       [[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]). 

上面代码被发现here

但是当我查询? - not_enemy(1,2)输出是真实的。

我不得不改用此长码:

not_enemy(A, B) :- 
      A #=1 #==> B #\= 2, 
      A #=4 #==> B #\= 6, 
      A #=4 #==> B #\= 7, 
      A #=4 #==> B #\= 9, 
      A #=9 #==> B #\= 11, 
      A #=12 #==> B #\= 14, 
      A #=14 #==> B #\= 16. 

任何人都可以请帮助纠正第一段代码?提前致谢。

+1

这个例子是错误的,并且混合使用'tuples_in/2'的通知肯定不是用CLP(FD)表达给定约束的好方法。你的代码是正确的方法(+1!)。另一种方法是应用方法@repeat描述:您可以构建关系的补充并使用tuples_in/2来将这些对约束为* compatible *元素。另一种方法是否定个别的'tuples_in/2'约束。要小心,尽管不会意外否定涉及多对的tuples_in/2约束,因为这不会在逻辑上等同于其他方式。 – mat

回答

5

我会改进你的代码,只是为了让通用

not_enemy(A, B) :- 
    maplist(not_enemy(A,B), [[1,2], [4,6], [4,7], [4,9], [9,11], [12,14], [14,16]]). 
not_enemy(A,B,[X,Y]) :- 
    X #= A #==> Y #\= B. 

我无法找到使用tuples_in来解决这个问题的适当方式。

3

以上使用tuples_in/2是错误的。

tuples_in定义为“兼容表”的思维方式: 然后,它应该是显而易见的,随着(#\=)/2组合不可能表达“不兼容表”工作。

为什么?因为---带有不兼容表---我们不希望排除任何单个不兼容的元组,但是所有 其中在同一时间。

当使用有限域时,我们可以通过以笛卡尔积作为消除不兼容对的基础,显式构造一个兼容性表。

+0

如何?兼容性表格? – false

+0

谢谢,我可以从概念上理解你的想法,我会在序言中尝试。 –

3

我找到了另一种答案,而不是使用此

not_enemy(A, B) :- 
    NotA #\= A #\/ NotB #\= B, 
    tuples_in([[NotA, NotB]], 
       [[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]). 

就否定tuples_in用#\

not_enemy(A, B) :- 
    #\ tuples_in([[A,B]], 
       [[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]). 
+1

它有用吗?很高兴知道!我认为\#是用于可约束的,而tuples_in不属于这个类别。所以我没有尝试... – CapelliC

+3

我检查了文档,如果经过进一步调查,你的答案证明是正确的,我将提交一份关于clpfd文档的错误报告 – CapelliC

+0

是的,它确实有效。 \#否定后面的任何内容(在clpfd中)。 –

1

扩展在我上面已经给出了评论,我想告诉你的SWI-Prolog顶层的一个重要特征,有助于检测出一个明显的错误表达问题。

首先考虑的not_enemy/2的明显错误的答案:

?- not_enemy(1, 2). 
true. 

但是,还有更多的它,你看到后,您可以使用:

?- set_prolog_flag(toplevel_residue_vars, true). 
true. 

然后,顶层显示待定由于涉及的变量未出现在查询中,通常不会显示剩余目标:

?- not_enemy(1, 2). 
% with pending residual goals 
_G454 in 0..1, 
_G454#\/_G460#<==>1, 
etc. 

由此可见,该公式存在一些问题:存在未决的剩余约束,CLP(FD)通常不会也不能保证待处理约束的一致性。您必须使用其中一个枚举谓词来查看是否有任何具体的解决方案。

在这种情况下,即使使用枚举谓词,也会得到错误的结果,因为问题被错误地表达出来。然而,单单待定的剩余约束已经给你一个清晰的表示,你不能把答案当作具体的解决方案。

标志toplevel_residue_vars通过隐式地将查询包装在名为call_residue_vars/2的重要谓词中工作。这在SICStus和SWI中可用来显示所有剩余约束。使用它来确保您不会在您的配方中某处意外地创建不可满足的约束。

由于这样的原因,我强烈建议你避免副作用,这样你可以更多地声明你的代码的原因,并使用顶层显示答案和具体的解决方案。