8皇后问题:在一个8X8方格的棋盘上,摆放8个皇后,要求任意两个皇后都不能在同一行、同一列、同一斜线上。求所有满足要求的摆放方法。
分析:这是一道经典的算法题目,可以用多种搜索方法来求解。
方法一:从题目本意出发,若不考虑约束条件,每个皇后都可以尝试放在64个方格中,可以用简单穷举算法,构造如下:
1 for p1:=1 to 64 do
2 for p2:=1 to 64 do
3 for p3:=1 to 64 do
4 ……
5 for p8:=1 to 64 do
6 if(任意两个皇后满足不在同一行、同一列、同一斜线上) then
7 输出该摆放方法。
显然,这种不加条件约束的穷举,需要64的8次方次搜索,时间不够用。因此如果用穷举,需要加约束条件减少搜索次数。
方法二:题目已经规定了任意两个皇后不能位于同一行,那么就可以假定第1个皇后位于第一行,第2个皇后位于第二行……第8个皇后位于第八行。这样,每个皇后只需要在8个列的位置中进行选择:
Code
1 for p1:=1 to 8 do
2 for p2:=1 to 8 do if p2<>p1 then
3 for p3:=1 to 8 do if p3<>p2 then
4 ……
5 for p8:=1 to 8 do
6 if(任意两个皇后满足不在同一列、同一斜线上) then
7 输出该摆放方法。
这个程序只需要8的8次方次运算。
方法三:进一步考虑,若第i个皇后已经占用了第k列,则第i+1、i+2……、第n个皇后都没有必要考虑尝试第k列了。我们可以为每列设计一个标志变量,若该列已经被占用,则将该标志变量变为true,在后面的循环中,直接跳过标记为true的列。
Code
1 var flag:array[1..8] of boolean;
2 begin
3 for i:=1 to 8 do
4 flag[i]:=false;
5 for p1:=1 to 8 do
6 begin
7 flag[p1]:=true;
8 for p2:=1 to 8 do if not flag[p2] then
9 begin
10 flag[p2]:=true;
11 ……
12 for p8:=1 to 8 do if not flag[p8] then
13 if 任意两个皇后满足不在同一斜线上) then
14 输出该摆放方法。
15 ……
16 flag[p2]:=false;
17 end;
18 flag[p1]:=false;
19 end;
20 end;
方法四:回溯
对于每个皇后的摆放位置都要进行试探和纠正,这就是“回溯”的思想。在N个皇后未放置完成前,摆放第I个皇后和第I+1个皇后的试探方法是相同的,因此完全可以采用递归的方法来处理。
算法结构如下:
Procedure Try(I:integer);{搜索第I行皇后的位置}
var j:integer;
begin
if I=n+1 then 输出方案;
for j:=1 to n do
if 皇后能放在第I行第J列的位置 then begin
放置第I个皇后;
对放置皇后的位置进行标记;
Try(I+1)
对放置皇后的位置释放标记;
End;
End;
Code
1 program N_Queens;
2 const
3 MaxN = 100; {最多皇后数}
4 var
5 A:array [1..MaxN] of Boolean; {竖线被控制标记}
6 B:array [2..MaxN * 2] of Boolean; {左上到右下斜线被控制标记}
7 C:array [1-MaxN..MaxN-1] of Boolean;{左下到右上斜线被控制标记}
8 X: array [1 .. MaxN] of Integer; {记录皇后的解}
9 Total: Longint; {解的总数}
10 N: Integer; {皇后个数}
11
12 procedure Out; {输出方案}
13 var
14 I: Integer;
15 begin
16 Inc(Total); Write(Total: 3, ':');
17 for I := 1 to N do Write(X[I]: 3);
18 Writeln;
19 end;
20
21 procedure Try(I: Integer);
22 {搜索第I个皇后的可行位置}
23 var
24 J: Integer;
25 begin
26 if I = N + 1 then Out; {N个皇后都放置完毕,则输出解}
27 for J := 1 to N do
28 if A[J] and B[J + I] and C[J - I] then begin
29 X[I] := J;
30 A[J] := False;
31 B[J + I] := False;
32 C[J - I] := False;
33 Try(I + 1); {搜索下一皇后的位置}
34 A[J] := True;
35 B[J + I] := True;
36 C[J - I] := True;
37 end;
38 end;
39
40 begin
41 Write('Queens Numbers = ');
42 Readln(N);
43 FillChar(A, Sizeof(A), True);
44 FillChar(B, Sizeof(B), True);
45 FillChar(C, Sizeof(C), True);
46 Try(1);
47 Writeln('Total = ', Total);
48 end.
浙公网安备 33010602011771号