我正在Prolog学习SWI Prolog实施的普遍考试。
我对如何使用排列解决问题的8版皇后问题的工作有一些疑问:
solution(Queens) :-
permutation([1,2,3,4,5,6,7,8], Queens),
safe(Queens).
permutation([],[]).
permutation([Head|Tail],PermList) :-
permutation(Tail,PermTail),
del(Head,PermList,PermTail).
del(Item,[Item|List],List).
del(Item,[First|List],[First|List1]) :-
del(Item,List,List1).
safe([]).
safe([Queen|Others]) :-
safe(Others),
noattack(Queen,Others,1).
noattack(_,[],_).
noattack(Y,[Y1|Ylist],Xdist) :-
Y1-Y=\=Xdist,
Y-Y1=\=Xdist,
Dist1 is Xdist + 1,
noattack(Y,Ylist,Dist1).
在之前的分辨率中,我使用了这个解决方案模板:[1 \ Y1,2 \ Y2,3 \ Y3,4 \ Y4,5 \ Y5,6 \ Y6,7 \ Y7,8 \ Y8]只是简单地说每个女王必须在不同的行上,X calue可以被约束。
这个版本的程序非常不同,因为我们可以观察到为了防止垂直攻击所有的皇后都必须在不同的行上,所以我每行都有一个女王。
因此,在不丢失信息的情况下,我可以说解决方案将是列表的排列: [1,2,3,4,5,6,7,8] 在每个元素中rappresent女王的Y坐标。
所以在这种情况下,我只是通过Y坐标(行指数)来表示皇后位置
所以我有解决方案关系,而不是说如果Queens是 [1,2,3,4]的前提,列表 Queens 是一个解决方案5,6,7,8] 原始列表,如果此排列安全(此排列列表中的每个女王都不会攻击其他女王)。
好的,这很清楚......现在它被定义为安全关系。
有一个基本案例表明,如果列表为空,那么这是安全的,因为没有攻击。
有一个普遍的情况,列表不是空的。如果列表不为空,我可以将其分为 [Queen | Others] ,其中女王是列表中的第一位女王和其他是剩余的子列表...所以原始列表 [Queen | Others] 是安全的,如果子列表其他它本身就是一个解决方案(如果它是安全的,如果没有攻击在其他情况下)如果第一项女王不攻击其他女王子列表......
好的......直到现在我觉得我很清楚......
现在我对 noattack 关系的定义存在一些问题!!!
问题在于我只通过Y坐标和X坐标来表示皇后位置 没有明确存在。
我明白,为了规避这种局限性,有一种普遍化(我希望能够很好地理解......我不太确定......):**我也知道必须有一个女王在每个栏目的栏目上,所以与名单中的第一个女王(女王)和子列表的X距离必须为1 **
距离第一项皇后和子列表的距离其他是距离第一项皇后和距离它最近的女王的X距离,是不是我的理由?
所以如果女王在不同的列上(对于构造总是如此), noattack 关系为TRUE,我可以表示必须在不同的行上说明与Queen的X距离和最近的其他子列表中的女王是1。
但是,如果我的推理是真的,我发现很难找到在这部分代码中如何理解这件事:
noattack(Y,[Y1|Ylist],Xdist) :-
Y1-Y=\=Xdist,
Y-Y1=\=Xdist,
Dist1 is Xdist + 1,
noattack(Y,Ylist,Dist1).
答案 0 :(得分:2)
我认为你的问题只有这两行:
Y-Y1=/=Xdist,
Y1-Y=/=Xdist,
它检查具有Y的女王是否以对角线的方式攻击Xdist距离的行中的女王。 (|Y - Y1| = Xdist --> diagonal attack
)。
[1,2,3,4,5,6,7,8]
的排列而发生。所以像[1,1,3,4,5,6,7,8]
之类的东西永远不会发生,这足以检查对角线。
我希望它能解决问题。
P.S。请注意Y1
是规则Others
中Safe/1
头部的Y坐标。所以它最初是Xdist
为1的女王,然后它回溯到其他行。
我们在讨论noattack/3
。你给它三个参数:
第一个:Y
当前女王的坐标,
第二次:最右边的列表 [Y1| Ylist]
在 Y
之后的某处开始在列表中,并继续到主列表的末尾。(是的,这是解决方案的子列表)和
第三:Xdist
是当前女王(有Y)和女王之间的索引距离,后者将与当前女王(有Y1和是第二个论点的负责人。)
第三个参数是必要的,因为没有它我们不能检查当前女王和具有Y1的女王之间的对角线交互。它是真正的基础数学,你在坐标系中只有2个点,只有自然数。让我们说这两个点以对角方式相互攻击,如果且仅 - 如果 abs(x1 - x2)= abs(y1 - y2)。
示例#1。如果你理解我的解释,请将其视为已接受。
P1 =(3,4)和P2 =(1,2) -->
这些点有对角线攻击,因为 abs(3-1)= abs(4 -2)= 2
示例#2
P1 =(3,4)和P2 =(7,0) -->
这些点有对角线攻击,因为 abs(3-7)= abs(4 -0)= 4
这就是我们检查 Y1-Y =\= Xdist
和 Y-Y1 =\= Xdist
的原因。因为只要有对角线攻击,其中至少有一个就是true
。当它们不是真的时,意味着女王Y
和女王Y1
之间没有对角线攻击。所以我们可以继续检查Ylist
的头部下一个女王。
我希望这就够了。这是一个非常容易的问题,请仔细阅读,如果您再也无法理解,请尝试自己在一张纸上追踪算法。这种方式总能奏效。
答案 1 :(得分:0)
当使用C解决递归中的相同问题时,我也有同样的困惑。对角线攻击有两种可能的方向。每个正方形的数字,x,y坐标,左上角为0,0。然后,您将看到这两个攻击对角线检测或计算满足条件:
我在C等式表示法中注释了上面的比较而不是Prolog表示法。在两点(x1,y1)和(x2,y2)之间,如果满足上述条件之一,则存在对角线攻击。