“八皇后问题”是算法与数据结构中的经典问题,是回溯算法的代表,也是栈的重要应用。不懂什么是“八皇后”?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)); //所有分支均已或穷举或剪枝之后,算法结束 } /************************************************************************************/
运行结果: