求PASCAL递归八皇后程序,加解析,要在FREE PASCAL上过了的,事后给分

 我来答
5wukequn
2011-02-26
知道答主
回答量:5
采纳率:0%
帮助的人:7846
展开全部

问题分析:

    为了解决这个问题,我们把棋盘的横坐标定为i,纵坐标定为j,i与j的值都是从1到n。 当某个皇后占了位置(i,j)时,在这个位置的垂直方向,水平方向和斜线(两条斜线)方向都不能再放其它皇后了。显然n个皇后肯定是对应不同的i值,也即是在i的每一个值上都有一个皇后,现在的关键问题是求出每一个皇后的j坐标。

    根据回溯法思想,从一条路往前走,能进则进,不能进则退,换一条路再试,直到所有路径都到试。按照此思想,直到第1个皇后的n-1个位置都试完,就可以得到全部的解,算法框架如下:

1、初始化棋盘为空

2、为皇后1选择合适位置

   为第i个皇后选择合适位置的过程算法如下:

  for j:=1 to n do

     if (i,j)位置为空  then 

        begin

         占用位置(i,j)

         if i<n then  为i+1个皇后选择合适的位置 {实际是对此过程的递归调用}

                else 输出一个解 {输出数组x}

          释放位置(i,j)

         end                      

下面以“四皇后问题”为例给出带“回溯”的一棵四叉树。 

 

上图中只有A结点是合法布局。其余叶结点都不是合法布局。

上述算法中,较困难和关键的一步,是如何检查所选择的皇后位置(i,j)是否安全,即不被前面已放好的皇后攻击。下面我们就来解决这个问题。根据上述规则应检查以下3项要求:

(1)不在同一行;

(2)不在同一列;

(3)不在同一对角线;

第一个要求在用数组x表示状态时已解决;

第二个要求我们用标志数组a,如果第j列已放了皇后,则有:a[j]=TRUE

      

 第三项检查对角线的问题,我们先分析一下同一对角线上的棋子的位置关系。我们发现,对于从右上到左下的对角线,例如:(6,6),(7,5),(8,4)…,类似地可发现有规律:i + j = 常数。此常数最小为1+1=2,最大为n+n=2*n,所以可以用数组b[2..2*n]来表示。对于从左上到右下的对角线,如:(1,3),(2,4),(3,5),(4,6)…,同一对角线的位置坐标i–j = 常数,这个常数,不同的对角线不一样,最小为1-n=-n+1,最大为n-1=n-1,因此我们也可以用一个标志数组c[-n+1..n-1]来表示它。

   

   这样如果我们在第i行第j列上放置了皇后,则只要设置:a[j]=False;c[i-j]=False;b[i+j]=False;就可以解决是否被攻击的问题。为了方便起见我们把数组a、b、c的下标说明为子界类型-n+1..2*n。数组x记录每组解的排列。

非递归

program N_Queens;

const   MaxN = 100;       {最多皇后数}

 var

   A:array [1..MaxN] of Boolean;   {竖线被控制标记}

   B:array [2..MaxN * 2] of Boolean;  {左上到右下斜线被控制标记}

   C:array [1-MaxN..MaxN-1] of Boolean;{左下到右上斜线被控制标记}

   X: array [1 .. MaxN] of Integer;   {记录皇后的解}

   Total: Longint;   {解的总数}

   N: Integer;     {皇后个数 }

 procedure Out;{输出方案}

   var

     I: Integer;

   begin

     Inc(Total);

     Write(Total: 3, ':');

     for I := 1 to N do  Write(X[I]: 3);

     Writeln;

   end;

procedure Main;

var

     K: Integer;

begin

     X[1] := 0; K := 1;

     while K > 0 do begin

       if X[K] <> 0 then begin

           A[X[K]] := True;

           B[X[K] + K] := True;

           C[X[K] - K] := True;

       end;

       Inc(X[K]);

       while(X[K]<=N)and not(A[X[K]]and B[X[K]+K]and C[X[K]-K])do

         Inc(X[K]);    {寻找一个可以放置的位置}

       if X[K] <= N then

          if K = N then Out

          else begin

             A[X[K]] := False;

             B[X[K] + K] := False;

             C[X[K] -K] := False;

             Inc(K);

             X[K] := 0;   {继续放置下一个皇后}

          end

        else  Dec(K);    {回溯}

      end;

end;

 begin

   Write('Queens Number = ');

   Readln(N);

   FillChar(A, Sizeof(A), True);

   FillChar(B, Sizeof(B), True);

   FillChar(C, Sizeof(c), True);

   Main;

   Writeln('Total = ', Total);

 end.

program N_Queens;

 const

   MaxN = 100;     {最多皇后数}

 var

   A:array [1..MaxN] of Boolean;   {竖线被控制标记}

   B:array [2..MaxN * 2] of Boolean;  {左上到右下斜线被控制标记}

   C:array [1-MaxN..MaxN-1] of Boolean;{左下到右上斜线被控制标记}

   X: array [1 .. MaxN] of Integer;   {记录皇后的解}

   Total: Longint;   {解的总数}

   N: Integer;     {皇后个数}

 procedure Out;    {输出方案}

   var

     I: Integer;

   begin

     Inc(Total); Write(Total: 3, ':');

     for I := 1 to N do  Write(X[I]: 3);

     Writeln;

   end;

递归:

 procedure Try(I: Integer);

{搜索第I个皇后的可行位置}

   var

     J: Integer;

   begin

     if I = N + 1 then Out;   {N个皇后都放置完毕,则输出解}

     for J := 1 to N do

       if A[J] and B[J + I] and C[J - I] then begin

         X[I] := J;

         A[J] := False;

         B[J + I] := False;

         C[J - I] := False;

         Try(I + 1);    {搜索下一皇后的位置}

         A[J] := True;

         B[J + I] := True;

         C[J - I] := True;

       end;

   end;

 begin

   Write('Queens Numbers = ');

   Readln(N);

   FillChar(A, Sizeof(A), True);

   FillChar(B, Sizeof(B), True);

   FillChar(C, Sizeof(C), True);

   Try(1);

   Writeln('Total = ', Total);

 end.

水镜光明3461
2011-02-24 · TA获得超过325个赞
知道小有建树答主
回答量:176
采纳率:0%
帮助的人:227万
展开全部
这是我亲手编的.. 绝不是 c&p..

PROGRAM e710;
VAR
x:ARRAY[1..8]OF integer;
a,b,c:ARRAY[-7..16]OF boolean; {-7,16是观察棋盘得出的边界,看完后面就明白了}
i,g:integer;
PROCEDURE print(Var g:integer); {打印棋盘}
VAR k,j,h:integer;
BEGIN
IF g MOD 16=0
THEN readln; {每输出16个棋盘暂停一次,方便检查.}
writeln('means',g); {输出有第g种方法.可有可无.}
FOR j:=8 DOWNTO 1 DO
BEGIN
FOR k:=1 TO 16 DO write('_');
writeln;
FOR k:=1 TO 8 DO
IF x[k]=j
THEN BEGIN
FOR h:=1 TO k-1 DO write(' |');
write('Q|'); {Q代表皇后}
FOR h:=k TO 7 DO write(' |')
END;
writeln
END;
inc(g)
END;
PROCEDURE try(i:integer); {这里是核心了}
VAR j:integer;
BEGIN
FOR j:=1 TO 8 DO {j是棋盘的纵坐标,i是横坐标,画图可以看出只需循环j. }
IF a[j]AND b[i+j]AND c[i-j] {判断该格子是否被占, i+j和i-j都是这一个的斜线方向,自己画图就懂,若被占了直接返回上面的循环..该格子为空则继续下面 }
THEN BEGIN
x[i]:=j; {记录第i个皇后的纵坐标}
a[j]:=false;b[j+i]:=false;c[i-j]:=false; {将该格子占领}
IF i<8 {,i=8时,即排到 第八个皇后的时候,就打印棋盘}
THEN try(i+1) {没到第八个时则继续递归, 求i+1的皇后的位置}
ELSE print(g);
a[j]:=true;b[i+j]:=true;c[i-j]:=true
END;
END;
BEGIN
FOR i:=-7 TO 16 DO
BEGIN
a[i]:=true;b[i]:=true;c[i]:=true
END;
g:=1;
try(1)
END.

说的很详细了. 看不懂就补充提问吧.. 谢谢.. 打字辛苦呀.
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
Such_Easy
2011-02-25 · 超过18用户采纳过TA的回答
知道答主
回答量:40
采纳率:0%
帮助的人:0
展开全部
位运算版本要吗
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(1)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式