2013-08-02 38 views
0

女王统治 给定一个n×n板,统治数量是攻击或占领每个方块所需的皇后(或其他棋子)的最小数量。对于n = 8,女王的统治数字为5. 编写谓词解析(N),以获得覆盖所有方块所需的最小皇后数。女王统治

+2

N皇后问题是不同的:找到一个安置皇后不相互攻击。 – CapelliC

+0

当然,我的问题是:给定一个n×n棋盘,找到控制号码,这是攻击或占用每个方块所需的最少皇后数量。对于n = 8女王的统治数字是5. – user2585677

+0

嗨,CapelliC,上面的代码是你在另一个问题中的答案。你能否提供一些关于我的问题的提示?我看到了一些算法,但我仍然不知道如何解决皇冠统治问题。 – user2585677

回答

4

这里是一个愚蠢的“所有解决方案”片段:

queens_coverage(N, Places) :- 
    findall(X/Y, (between(1,N,X), between(1,N,Y)), B), 
    placement(B, [], Places). 

placement([], Placement, Placement). 
placement(Unplaced, SoFar, Placement) :- 
    select(Place, Unplaced, Places), 
    remove_attacks(Place, Places, Remains), 
    placement(Remains, [Place|SoFar], Placement). 

remove_attacks(X/Y, [U/V|Places], Remains) :- 
    (U == X ; V == Y ; abs(U-X) =:= abs(V-Y)), 
    !, remove_attacks(X/Y, Places, Remains). 
remove_attacks(P, [A|Places], [A|Remains]) :- 
    remove_attacks(P, Places, Remains). 
remove_attacks(_, [], []). 

如置换的问题通常,该代码是没有希望的低效:

?- setof(L-Ps, (queens_coverage(4,Ps),length(Ps,L)), R), length(R, T). 
R = [3-[1/1, 2/3, 4/2], 3-[1/1, 2/4, 3/2], 3-[1/1, 2/4, 4/3], 3-[1/1, 3/2, 2/4], 3-[1/1, 3/4, .../...], 3-[1/1, .../...|...], 3-[.../...|...], 3-[...|...], ... - ...|...], 
T = 144. 

?- setof(L-Ps, (queens_coverage(5,Ps),length(Ps,L)), R), length(R, T). 
R = [3-[1/1, 2/4, 4/3], 3-[1/1, 3/4, 4/2], 3-[1/1, 3/4, 5/3], 3-[1/1, 3/5, 4/3], 3-[1/1, 4/2, .../...], 3-[1/1, .../...|...], 3-[.../...|...], 3-[...|...], ... - ...|...], 
T = 2064. 

?- setof(L-Ps, (queens_coverage(6,Ps),length(Ps,L)), R), length(R, T). 
R = [4-[1/1, 2/3, 3/6, 6/2], 4-[1/1, 2/3, 6/2, 3/6], 4-[1/1, 2/4, 4/5, 5/2], 4-[1/1, 2/4, 4/5, .../...], 4-[1/1, 2/4, .../...|...], 4-[1/1, .../...|...], 4-[.../...|...], 4-[...|...], ... - ...|...], 
T = 32640. 

?- setof(L-Ps, (queens_coverage(7,Ps),length(Ps,L)), R), length(R, T). 
ERROR: Out of global stack 

当然,存储所有的列表是一个真正的浪费。

?- integrate(min, qc(7), R). 
R = 4-[1/2, 2/6, 4/1, 5/5] . 

?- integrate(min, qc(8), R). 
R = 5-[1/1, 2/3, 3/5, 4/2, 5/4] 

而不是select/3您应该应用适当的启发式。一个简单的一个可能是贪婪的选择......

编辑

这里是集成:

integrate(min, Goal, R) :- 
    State = (_, _), 
    repeat, 
    ( call(Goal, V), 
     arg(1, State, C), 
     ((var(C) ; V @< C) -> U = V ; U = C), 
     nb_setarg(1, State, U), 
     fail 
    ; arg(1, State, R) 
    ), 
    !. 

nb_setarg/3是SWI-Prolog的内置,ARG/3的ISO。如果你的Prolog错过了它们,你应该用assert/retract来取代 - 比如说。

集成需要谓词,并且与附加的参数调用它与所存储的当前最小进行比较:这里是:

qc(N, L-Ps) :- queens_coverage(N,Ps),length(Ps,L). 

作为贪婪启发式,安置的第二条款可以被替换通过

placement(Unplaced, SoFar, Placement) :- 
    integrate(min, peek_place_of_min_remain(Unplaced), (_Count,Place,Remains)), 
    !, placement(Remains, [Place|SoFar], Placement). 

peek_place_of_min_remain(Unplaced, (Count,Place,Remains)) :- 
    select(Place, Unplaced, Places), 
    remove_attacks(Place, Places, Remains), 
    length(Remains, Count). 
+0

嗨CapelliC, 1.我需要澄清我的问题:任何两个皇后允许互相攻击,也就是说两个皇后可以在同一排,柱或对角线上。 但是在你提供的解决方案中,似乎两个皇后不可能。我想稍微改变一下代码。你能否解释下面的条款真的这么做: remove_attacks(P,[A | Places],[A | Remains]): - remove_attacks(P,Places,Remains)。 我有点困惑。现在我再次陷入困境。 – user2585677

+0

2.你的建议是对的,我应该使用贪婪的启发式。我想出了一个启发式的,但我不知道如何在序言中实现。启发式 函数是h =#(未覆盖方块)。具体而言,每次我们选择这样的方形来放置一次将皇后放在正方形上的皇后时,剩下的未被覆盖的正方形的数量是最少的。 3.您能否在命令'integrate(min,qc(7),R)'中提供谓词“integrate”的代码。 – user2585677

+0

现在我了解了'整合'的细节。并等待更多指导。 – user2585677