我的課後作業:N皇后問題


“八皇后問題”是算法與數據結構中的經典問題,是回溯算法的代表,也是棧的重要應用。不懂什麼是“八皇后”?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)); //所有分支均已或窮舉或剪枝之後,算法結束
}
/************************************************************************************/


運行結果:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章