用递归和栈的方法实现N皇后求解

本文介绍了使用递归和栈两种方法解决N皇后问题的思路。递归方法从第一行开始,逐行放置皇后,判断当前位置是否安全。栈方法通过创建栈存储皇后位置,不断尝试放置皇后并检查安全性,若无法放置则回溯。两种方法都能找到所有解决方案,但随着N增大,运算复杂度增加,可能导致效率降低。
摘要由CSDN通过智能技术生成

 

N皇后问题的栈和递归实现方式

 

八皇后问题:初始状态下,国际象棋棋盘上没有任何棋子。顺序的在棋盘上的第一行、第二行、、第八行上面布放棋子。每一行的八个位置可以放置皇后,要求任意时刻,棋盘的合法布局满足三个条件,即任何两个棋子不得摆放在棋盘上的同一行、同一列及同一对角线上。当棋盘的大小为N时,就变成了N皇后问题。解决这个问题,最简单的办法是用递归,也可以借助栈来加以实现。

用递归的办法解决N皇后问题:首先,将棋盘初始化为一个二维数组,从第0行第0列开始寻找适合的位置放置皇后。然后顺序的处理第二行、第三行、、第八行,完成一次排列。处理每一行的时候,需要循环8次来找出所有满足条件的排列。在某一行寻找适合位置的时候,需要对该行的每个位置进行安全检查,若安全则放置棋子,否则,循环后移判别下一个位置。当在第八行找到安全位置时,则一次排列探测成功,输出当前的棋盘状态,并将排列计数增加1。否则,继续在下一行进行同样的操作。就这样,直到所有的排列被穷尽搜索。

      借助栈的方法实现N皇后问题的求解:首先,同样设置一个二维字符数组表示棋盘chess的状态,设置棋盘上的每个位置结点信息(包括行列信息及是否有放过皇后true/false)。然后,设置三个一维占用记录数组,分别为:列被占用(大小为MaxSize)、正斜对角线被占用(/)、反斜对角线被占用(/),其中正反对角线占用数组均为2*MaxSize-1,将棋盘的所有结点占用信息全部初始化为false。此时,开始从第一行起处理N皇后放置问题。

       将第一列从后向前一次入栈,即chess[0][0]位于栈顶。取栈顶元素getTop(Node&node)(不是出栈操作),判别是否放过皇后:

(1)、若没有放过则往下进行:判断对角及列占用与否,若被占用则出栈进行后一位置的判别,否则,该位置放置皇后并更改结点位置信息及棋盘在该位置的状态。此时,将栈顶元素取出,并将该节点入栈。若当前行已经是最后一行,则表明一次探索成功,输出棋盘的状态,并将计数值增加1。否则,继续将下一行位置结点从后向前读进栈,重复前面的操作。

(2)、若放过,则表明前面已经成功找到n种合符要求的摆放方法,当前是在寻求新的摆放方法。因此,应将当前节点的信息初始化为未放置过皇后的状态结点,然后,继续(1)中的操作直至穷尽。

两种方法均能实现N皇后的问题求解,但是实现方式却迥然不同。递归需要很多次的自身函数调用,当N很大的时候可能造成溢出问题。栈虽然实现方式不一样,但是,当N很大的时候,仍然会需要很长的时间来进行运算,这是由于算法本身是利用穷举的原则来进行问题的求解,因此,这也是不可避免的。当N增加时,其运算复杂度可能会呈指数次的增长。当N=4时,只有2中排列方式;N=8时就有92种,而当N=10时就到了724种;当N=12时,排列总数达到了14200种之多,可见复杂度不见一般。

下面附上两种方法的C++源代码:

//递归方法

/*******************************************************

Copyright@2009-2011 by hank(SiChuan University)

*******************************************************/

//NQueen.h

#ifndef NQUEEN_H

#define NQUEEN_H

#include<string.h>

//#include<cstdlib>

//n皇后问题类定义

const int MaxSize=7;

class NQueen

{

      int count;//问题解法数

      char ChessState[MaxSize][MaxSize];//棋盘状态

      bool SafeJudge(int row,int col)/*const*/;//安全性检查

      void PlaceQueen(int row);//放置皇后  

public:

      NQueen();//构造函数

      ~NQueen(){}//析造函数

      void Solve();//解决N皇后问题

      int getCount(){ return count;}//N种放置方法

      void Display();//显示

 

};

 

#endif

/******************************************************

Copyright@2009-2011 by hank(SiChuan University)

*******************************************************/

//NQueen.cpp

#include"NQueen.h"

#include<iostream>

#include<fstream>

using namespace std;

/******************************************/

//构造函数

NQueen::NQueen()

{

      count=0;

      for(int i=0;i<MaxSize;i++)

           for(int j=0;j<MaxSize;j++)

           ChessState[i][j]='-';

}

/******************************************/

//安全性检查

bool NQueen::SafeJudge(int row,int col)/*const*/

{

      int i,j;

      for(i=0;i<row;i++)//判断同列是否有Q

      {

           if(ChessState[i][col]=='Q')

                 return false;

      }

      for(j=0;j<col;j++)//判断同行是否有Q

      {

           if(ChessState[row][j]=='Q')

                 return false;

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值