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;