当前位置:   article > 正文

八皇后问题(递归+非递归)_9.a使用递归和非递归完成8皇后问题,若棋盘为5x5或9x9结果如何?总结递归与非递归算

9.a使用递归和非递归完成8皇后问题,若棋盘为5x5或9x9结果如何?总结递归与非递归算

一.问题描述

在8×8格的国际象棋棋盘上放置八个皇后,使得任意两个皇后不能互相攻击,即任何行、列或对角线(与水平轴夹角为45°或135°的斜线)上不得有两个或两个以上的皇后。这样的一个格局称为问题的一个解。请用递归与非递归两种方法写出求出八皇后问题的算法。

二.解题思路描述

一个正确的解应当是每一列,每一行,每一条斜线上均只有一个皇后。

对于递归算法,本人才有模拟的方式进行,而且,我觉得开辟一个二维数组更显而易见。首先,从空棋盘开始摆放,保证第m行m个皇后互不攻击,然后摆放第m+1个皇后。当然对于第m+1个皇后可能有多种摆放方法,由此,我必须一一枚举,采用回溯策略是可行且合乎逻辑的。 

而对于非递归算法,我只是借助于书本上一个递归改为非递归的框架,依次搭建而已。

在此过程中,我采用一维数组,一位对于八皇后问题,每一行不可能存在二个及二个以上的皇后,board[i]表示第i行棋盘摆放的位置为第board[i]列。递归方法借助于系统提供的栈,而我非递归算法的实现,仅仅是自己构造一个栈而已。

递归解法

 

#include <iostream>
#include <cstdio>
#include <sys/timeb.h>
using  namespace std;

const  int MAX_SIZE =  100;
enum flag  {blank = 'X',queen =  1 };

char Chess [MAX_SIZE ] [MAX_SIZE ]; //棋盘图
int n; //解决n皇后问题
int total; //用于计摆放方式


void Init ( )
{ //对棋牌进行初始化
         for ( int i =  0; i < n; i++ )
                 for ( int j =  0; j < n; j++ )
                        Chess [i ] [j ] = blank;
        total =  0; //初始时有零中摆放方式
}

bool Judge ( int r, int c )
{ //判断(r,c)位置是否可放置
         int i,j;
         for (i = r +  1; i < n; i++ )
                 if (Chess [i ] [c ] == queen )
                         return  false; //说明c列上已有一皇后
         for (i = c +  1; i < n; i++ )
                 if (Chess [r ] [i ] == queen )
                         return  false; //说明r行上已有一皇后
         for (i = r +  1, j = c +  1(i < n ) &&  (j < n ); i++, j++ )
                 if (Chess [i ] [j ] == queen )
                         return  false; //45度斜线上已有一皇后
         for (i = r +  1, j = c -  1(i <n ) &&  (j >=  0 ); i++, j-- )
                 if (Chess [i ] [j ] == queen )
                         return  false; //135度斜线上已有一皇后
         return  true; //排除四种情况后,说明(r,c)点可放置皇后
}

void Backtrack ( int k, int cnt )
{ //回溯算法主程序
        
         if (k <  0 || cnt == n ) //棋牌摆放完毕 or 以摆满n后
         {
                 if (cnt == n )
                 {
                         printf ( "No.%d:\n",++total );
                         for ( int i =  0; i < n; i++ )
                         {
                                 for ( int j =  0; j < n; j++ )
                                         printf ( " %c ",Chess [i ] [j ] );
                                 putchar ( '\n' );
                         }                     
                         putchar ( '\n' );
                 }
         }
         else
         {
                 int r = k / n, c = k % n;
                 if (Judge (r,c ) )
                 { //可放置一皇后
                        Chess [r ] [c ] = queen;
                        Backtrack (k -1,cnt +1 );
                        Chess [r ] [c ] = blank;
                 }
                Backtrack (k -1,cnt );
         }
        
}

int main ( )
{ //此为主函数
        timeb t1,t2;
         long kk;
        cout<< "输入皇后个数:";
         while (cin>>n )
         {
                        Init ( );
                        ftime (&t1 );
                        Backtrack (n*n -1, 0 );
                        ftime (&t2 );
                        cout<< "计算"<<n<< "后问题总共可有"<<total<< "种摆法!"<<endl;
                        kk =  (t2. time-t1. time )* 1000 + t2. millitm-t1. millitm;
                        cout<< "本次回溯耗时:"<<kk<< "毫秒"<<endl;
                         system ( "PAUSE" );
                        cout<< "输入皇后个数:";
         }
         return  0;
}
 

非递归解法

 

#include <iostream>
#include <sys/timeb.h>
#define N 100
using  namespace std;

int board [N ];
int n,sum;

void init ( )
{
         for ( int i =  1; i <= n; i++ )
                board [i ] =  0;
}

void display ( )
{
         int i,j;
        cout<< "No."<<sum<<endl;
         for (i =  1; i <= n; i++ )
         {
                 for (j =  1; j <= n; j++ )
                         if (board [i ] == j )
                                cout<< "Q ";
                         else
                                cout<< "X ";
                cout<<endl;
         }
        cout<<endl;
}

bool canPut ( int k )
{
         for ( int i =  1; i < k; i++ )
                 if ( ( abs (k - i ) ==  abs (board [k ] - board [i ] ) ) || board [i ] == board [k ] )
                         return  false; //1.是否在同一斜线;2.是否位于同一列
         return  true;
}

void Backtrack ( )
{
        board [ 1 ] =  0;
         int k =  1;
         while (k >  0 )
         {
                board [k ]++;
                 while ( (board [k ] <= n ) && ! (canPut (k ) ) )
                        board [k ] +=  1;
                 if (board [k ] <= n )
                         if (k == n )
                         {
                                sum++;
                                display ( );
                         }
                         else
                         {
                                k++;
                                board [k ] =  0;
                         }
                 else
                        k--;

         }
}

int main ( )
{
        timeb t1,t2;
         long kk;
        cout<< "输入皇后个数:";
         while (cin>>n )
         {
                init ( );
                sum =  0;
                ftime (&t1 );
                Backtrack ( );
                ftime (&t2 );
                cout<< "总共排列方式为:"<<sum<<endl;
                kk =  (t2. time-t1. time )* 1000 + t2. millitm-t1. millitm;
                cout<< "本次回溯耗时:"<<kk<< "毫秒"<<endl;
                 system ( "PAUSE" );
                cout<< "输入皇后个数:";
         }
         return  0;
}
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/825551
推荐阅读
相关标签
  

闽ICP备14008679号