一个简单的 3 步求解方法如下:
- 描述事实(检查)
- 结果生成你想要的,但让程序有选择
- 给出不适用的解决方案的规则
所以从2开始:
产生可能的结果。用简单的话想一想:对于每一个论点,我选择或不选择。可能或可能不是部分可以用 subsum
解决。{}
{choose(X)} :- argument(X).
甚至更简单:我从参数中选择一个子项
{choose(X):argument(X)}.
让我们用Potassco和#show choose/1.
共振模式检查解决方案enumerate all
:
Answer: 1
Answer: 2
choose(b)
Answer: 3
choose(c).
..
Answer: 15
choose(a) choose(b) choose(c)
Answer: 16
choose(a) choose(b) choose(c) choose(d)
SATISFIABLE
找到所有组合。是时候删除错误的东西了。再说一遍:用简单的话想一想:我不可能选择两个论点来攻击另一个论点。(如果头部保持打开状态,则读取为 False。)
:- choose(X), attack(X,Y), choose(Y).
现在再次检查:
Answer: 1
Answer: 2
choose(a)
Answer: 3
choose(d)
Answer: 4
choose(a) choose(d)
Answer: 5
choose(c)
Answer: 6
choose(a) choose(c)
Answer: 7
choose(b)
Answer: 8
choose(b) choose(d)
SATISFIABLE
现在我们需要确保每个未选择的参数都受到至少一个选择的元素的攻击:
1 {choose(Y):attack(Y,X)} :- argument(X), not choose(X).
读取:对于每个X
未选择的参数,攻击它的已选择参数的数量至少为一个。
让我们检查一下:
Answer: 1
choose(a) choose(d)
SATISFIABLE
好的。
由于约束通常是用空头来制定的,让我们重新制定最后一条规则:
:- argument(X), not choose(X), {choose(Y):attack(Y,X)} 0.
读取:没有参数X
,没有被选择,并且有最多 0 个选择的参数,它攻击X
。它提供相同的输出。
完整代码:
argument (a;b;c;d).
attack (a,b).
attack (b,c).
attack (d,c).
{choose(X):argument(X)}.
:- choose(X), attack(X,Y), choose(Y).
:- argument(X), not choose(X), {choose(Y):attack(Y,X)} 0.
#show choose/1.