博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

8皇后问题

Posted on 2010-11-01 15:55  桃子在路上  阅读(458)  评论(0)    收藏  举报

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.