c++語言描述n皇后問題(回溯法)

第一種方法:
思路:我們以4皇后問題爲例:用回溯法,設一個二維數組作爲棋盤,一個位置一個位置地試,首先我們將第一個皇后放入(0,0)中,根據規則,第0行中不能再放其他皇后,那麼下一個要放在第二行,根據規則,第1行第一二列被第一個皇后監視,所以只能放入(1,2)中,繼續下一行,我們發現沒有位置可以放,那麼說明上一個皇后要換位置,所以回退一行,將上一個皇后放入(1,3),再找下一個位置,如此反覆,直到求出全部解。
在這裏插入圖片描述
代碼:
queens.cpp

#include<iostream>

using namespace std;

const int max_board = 30;  //最多可解決30皇后問題

class Queens {
public:
   Queens(int size);  //構造函數
   bool is_solved() const;  //判斷是否已經解決了問題
   void print() const;  //打印出結果
   bool unguarded(int col) const; //判斷這個位置是否可以放新的皇后
   void insert(int col); //放入新的皇后
   void remove(int col); //回退
   int  board_size; //要解決的是board_size皇后問題
private:
   int  count;      //表示放入的皇后數,也表示行數
   bool queen_square[max_board][max_board];  //用二維數組來表示棋盤
};

void Queens::insert(int col)  //放入新的皇后
{
   queen_square[count++][col] = true; //將這個位置的值變爲true,表示放入了皇后,count加一
}

Queens::Queens(int size) //構造函數,參數爲要判斷的皇后大小
{
   board_size = size;
   count = 0; //初始時未放入皇后,在第0行
   for (int row = 0; row < board_size; row++)
      for (int col = 0; col < board_size; col++)
         queen_square[row][col] = false;  //開始時給每個位置賦初值false,表示還未放皇后
}

bool Queens::unguarded(int col) const  //判斷這個位置是否可以放新的皇后
{
   int i;
   bool ok = true; //表示是否可以放入皇后
   for (i = 0; ok && i < count; i++)
      ok = !queen_square[i][col];    //檢測在同一列中是否有皇后
   for (i = 1; ok && count - i >= 0 && col - i >= 0; i++)
      ok = !queen_square[count - i][col - i];  //檢測主對角線上是否有皇后
   for (i = 1; ok && count - i >= 0 && col + i < board_size; i++)
      ok = !queen_square[count - i][col + i];  //檢測輔對角線上是否有皇后

   return ok;
}

void Queens::print() const //打印結果
{
    int row,col;
    int count = 0;
    for(col = 0;col < board_size;col++) cout << "--";
    cout << "--\n";
    for(row = 0;row < board_size;row++)
    {
        for(col = 0;col < board_size;col++)
        {
            count++;
            if(queen_square[row][col])
            {
                cout << " Q";
            } //一行一行檢測,如果值是true則說明該位置存了皇后
            else cout << " ."; //如果值是false則說明該位置存了皇后
            if(board_size  == count)
            {
                cout << endl;
                count = 0;
            }
        }
    }
}

void Queens::remove(int col)  //回退
{
    queen_square[--count][col] = false;
}

bool Queens::is_solved() const  //判斷是否已解決
{
    if(count == board_size) return true;  //如果放入皇后的個數等於問題中皇后的個數則說明問題已經解決
    else return false;
}

main.cpp

#include "queens.cpp"

void solve_from(Queens &configuration)  //解決問題
{
   if (configuration.is_solved()) configuration.print(); //如果問題已被解決,則打印出結果
   else
      for (int col = 0; col < configuration.board_size; col++) //遍歷數組
      {
         if (configuration.unguarded(col))
         {
            configuration.insert(col);  //如果該位置沒有被監控則放入皇后
            solve_from(configuration);   //遞歸
            configuration.remove(col);   //如果問題已經有一個解,那麼打印出這個解,回退,繼續尋找下一個解
         }
      }
}

void print_information()
{
    cout << "This program determines all the ways to place n queens\n" << "on an n by n chessboard,where n <= " << max_board << endl;
}
int main()
{
   int board_size;
   print_information();
   cout << "What is the size of the board? " << flush;
   cin  >> board_size;  //輸入要解決幾皇后問題
   if (board_size < 0 || board_size > max_board)
      cout << "The number must be between 0 and " << max_board << endl;  //如果輸入的值不合法則輸出提示信息
   else {
      Queens configuration(board_size); //實例一個對象
      solve_from(configuration);  //解決問題
   }
}

第二種方法:
思路:跟第一種方法類似,將二維數組換成一維數組,需要四個一維數組,一個用來存每行中皇后的位置的列數,兩個用來表示該條對角線上是否已經被皇后監視,還有一個用來表示該列中是否被皇后監視。主函數與方法一代碼相同。
代碼:

queens.cpp

#include<iostream>

using namespace std;

const int max_board = 30;  //最多可解決30皇后問題

class Queens {
public:
   Queens(int size); //構造函數
   bool is_solved() const;  //判斷是否已經解決了問題
   void print() const;  //打印出結果
   bool unguarded(int col) const; //判斷這個位置是否可以放新的皇后
   void insert(int col); //放入新的皇后
   void remove(int col); //回退
   int board_size; //要解決的是board_size皇后問題
private:
   int  count; //表示放入的皇后數,也表示行數
   bool col_free[max_board]; //用來表示該列中是否被皇后監視
   bool upward_free[2 * max_board - 1];//用來表示主對角線上是否已經被皇后監視
   bool downward_free[2 * max_board - 1];//兩個用來表示輔對角線上是否已經被皇后監視
   int  queen_in_row[max_board];  //用來存放入的皇后的列數
};

Queens::Queens(int size) //構造函數,參數爲要判斷的皇后大小
{
   board_size = size;
   count = 0;
   for (int i = 0; i < board_size; i++) col_free[i] = true;
   for (int j = 0; j < (2 * board_size - 1); j++) upward_free[j] = true;
   for (int k = 0; k < (2 * board_size - 1); k++) downward_free[k] = true;  //開始時所有值都爲true,表示可以放皇后
}

void Queens::insert(int col) //放入新的皇后
{
   queen_in_row[count] = col; //將列數存入數組中
   col_free[col] = false;  //該位置的列被監視
   upward_free[count + col] = false; //該位置的主對角線被監視
   downward_free[count - col + board_size - 1] = false;//該位置的輔對角線被監視
   count++;
}

bool Queens::unguarded(int col) const  //判斷這個位置是否可以放新的皇后
{
   return  col_free[col] && upward_free[count + col] && downward_free[count - col + board_size - 1]; //如果列,主對角線,副對角線中有一個被監視,則不能放皇后
}

void Queens::remove(int col) //回退
{
    count--;
    col_free[col]  = true;
    upward_free[count + col] = true;
    downward_free[count - col + board_size-1] = true;//將這個位置恢復
}

bool Queens::is_solved() const  //判斷是否已解決
{
    if(count == board_size) return true;  //如果放入皇后的個數等於問題中皇后的個數則說明問題已經解決
    else return false;
}

void Queens::print() const //打印結果
{
    int i,j;
    int count = 0;
    for(i = 0;i < board_size;i++) cout << "--";
    cout << "--\n";
    for(i = 0;i < board_size;i++)
    {
        for(j = 0;j < board_size;j++)
        {
            count++;
            if(j == queen_in_row[i]) cout << " Q";  //找出存皇后的列數,輸出Q
            else cout << " .";
            if(board_size  == count)
            {
                cout << endl;
                count = 0;
            }
        }
    }
}

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