“八皇后问题”是算法与数据结构中的经典问题,是回溯算法的代表,也是栈的重要应用。不懂什么是“八皇后”?SEE THIS
而N皇后问题是更普遍情况下的情况。这里给出我用C++实现的N皇后算法。
1.头文件stack.h
#ifndef _STACK_H_
#define _STACK_H_
#include "Vector.h" //以向量为基类
template <typename T> class Stack: public Vector<T> { //由向量派生的栈模板类
public: //size()、empty()以及其它开放接口均可直接沿用
void push(T const & e) { Insert(Size(), e); } //入栈
T pop() { return Remove(Size()-1); } //出栈
T& top() { return (*this)[Size()-1]; } //取顶
};
#endif
2.头文件queen.h
#ifndef _QUEEN_H_
#define _QUEEN_H_
//代码4.12
struct Queen { //皇后类
int x, y; //皇后在棋盘上的位置坐标
Queen(int xx = 0, int yy = 0) : x(xx), y(yy) {};
bool operator==(Queen const & q) { //重载判等操作符,以检测不同皇后之间可能的冲突
return (x == q.x) //行冲突(这一情况其实并不会发生,可省略)
|| (y == q.y) //列冲突
|| (x + y == q.x + q.y) //沿正对角线冲突
|| (x - y == q.x - q.y); //沿反对角线冲突
}
bool operator!=(Queen const & q) { return !(*this == q); } //重载不等操作符 /*DSA*/可否写成:return *this != q?
};
#endif
3.主程序main.cpp
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include "stack.h" //栈
#include "queen.h" //引入皇后类
typedef enum {Continuous, Step} RunMode;
RunMode runMode; //运行模式
int nSolu=0; //解的总数
int nCheck=0; //尝试的总次数
int count=0;//一个计数变量
int N = 0; //棋盘大小
FILE *file;//文件指针
#define QUEEN_MAX 20 //皇后最大数量
void placeQueens(int);
void displayRow(Queen& q, int);
void displayProgress(Stack<Queen>& S, int);
void printinfile(Queen& q);
/******************************************************************************************
* n皇后(迭代版)
******************************************************************************************/
int main() {
int start=0,nQueen=0;
cout<<"*************N皇后问题求解程序**************"<<endl<<endl;
cout<<"输入问题的规模,N= ";
cin>>nQueen;
N=nQueen;
cout<<endl<<"请选择:单步演示(输入1)还是查看结果(输入2) ";
cin>>start;
if(start==1) runMode=Step;
else runMode=Continuous;
placeQueens(nQueen); //启动查找
cout << endl << nSolu << " solution(s) found after "
<< nCheck << " check(s) for "
<< nQueen << " queen(s)\n" << endl ; //输出解的总数
return 0;
}
/********************************具体函数的实现******************************************/
void displayRow(Queen& q) { //打印当前皇后(放置于col列)所在行
printf("%2d: ", q.x);
int i = 0;
while (i++ < q.y) printf("[]");
printf("█");
while (i++ < N) printf("[]");
printf("%2d\n", q.y);
}
void displayProgress(Stack<Queen>& S, int nQueen) { //在棋盘上显示搜查的进展
system("cls");
N = nQueen; S.Traverse(displayRow);
if (nQueen <= S.Size())
cout << nSolu << " solution(s) found after " << nCheck << " check(s)\a";
getchar();
}
void printinfile(Queen& q)//在文件中打印结果
{
file=fopen("result.txt","a+");//创建文件存储结果
fprintf(file,"%2d: ",q.x);
int i=0;
while(i++ <q.y) fprintf(file,"[]");
fprintf(file,"█");
while(i++<N) fprintf(file,"[]");
fprintf(file,"%2d\n",q.y);
count++;
if(count>=N)//完整打印出一个解后,打印分隔
{
fprintf(file,"这是第%d个解-----------\n",nSolu);
count=0;
}
fclose(file);
}
//代码4.13
void placeQueens(int N) { //N皇后算法(迭代版):采用试探/回溯的策略,借助栈记录查找的结果
unlink("result.txt");//更新存储文件
Stack<Queen> solu; //存放(部分)解的栈
Queen q(0, 0); //从原点位置出发
do { //反复试探、回溯
if (N <= solu.Size() || N <= q.y) { //若已出界,则
q = solu.pop(); q.y++; //回溯一行,并继续试探下一列
} else { //否则,试探下一行
while ((q.y < N) && (0 <= solu.Find(q))) //通过与已有皇后的比对
{ q.y++; nCheck++; } //尝试找到可摆放下一皇后的列
if (N > q.y) { //若存在可摆放的列,则
solu.push(q); //摆上当前皇后,并
if (N <= solu.Size()) nSolu++; //若部分解已成为全局解,则通过全局变量nSolu计数
q.x++; q.y = 0; //转入下一行,从第0列开始,试探下一皇后
}
}/*DSA*/
/*选择的方式不同,选择不同的函数*/
if (Step == runMode) displayProgress(solu, N);
else
{
if(N<=solu.Size())
solu.Traverse(printinfile);
}
} while ((0 < q.x) || (q.y < N)); //所有分支均已或穷举或剪枝之后,算法结束
}
/************************************************************************************/
运行结果:
转载于:https://blog.51cto.com/fjwind/1211187