日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

递归/回溯:八皇后问题N-Queens

發(fā)布時(shí)間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 递归/回溯:八皇后问题N-Queens 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

N皇后問題是計(jì)算機(jī)科學(xué)中最為經(jīng)典的問題之一,該問題可追溯到1848年,由國(guó) 際西洋棋棋手馬克斯·貝瑟爾于提出了8皇后問題。
將N個(gè)皇后放擺放在N*N的棋盤中,互相不可攻擊,有多少種擺放方式,每種擺 放方式具體是怎樣的?

8皇后即 8*8的棋盤中,將8個(gè)皇后放置在棋盤上,且皇后之間無(wú)法倆倆攻擊到對(duì)方。

關(guān)于國(guó)際象棋中皇后的實(shí)力:國(guó)際象棋棋局中實(shí)力最強(qiáng)的一種棋子,也是最容易被吃掉的棋子。后可橫直斜走,且格數(shù)不限

類似4*4的棋盤上,有如下兩種皇后的放置方法:

.Q..
...Q
Q...
..Q...Q.
Q...
...Q
.Q..

分析:
N*N的棋盤放置N個(gè)皇后,即至少每一行需要一個(gè)皇后;

  1. 將一個(gè)皇后放置到棋盤上之后,棋盤如何演變(一個(gè)皇后放到棋盤,她的影響區(qū)域?yàn)樯?#xff0c;下,左,右,左上,左下,右上,右下)
  2. 針對(duì)每一個(gè)皇后,如何能夠確認(rèn)下一個(gè)皇后,以及下下一個(gè)皇后。。。直到能夠放置N個(gè)皇后的棋盤分布?

針對(duì)問題一,我們可以實(shí)現(xiàn)如下算法:
針對(duì)棋盤打標(biāo):

void mark_queen(int x, int y, std::vector<std::vector<int> > &mark) {/*維護(hù)兩個(gè)方向數(shù)組可以取到皇后的八個(gè)方向即可這里定義了const型是為了節(jié)省內(nèi)存,即整個(gè)進(jìn)程代碼運(yùn)行期間,此時(shí)的const兩個(gè)數(shù)組是存放在常量?jī)?nèi)存區(qū),且定義為了static,則整個(gè)代碼僅僅會(huì)有一份拷貝*/static const int dx[] = {0,0,-1,1,-1,1,-1,1}; static const int dy[] = {-1,1,0,0,-1,-1,1,1}; if (x < 0 || x > mark.size() || y < 0 || y > mark.size()) {return ;}mark[x][y] = 1;for (int i = 0;i < mark.size(); ++i) {for (int j = 0;j < 8; ++j) {int new_x = x + i * dx[j];int new_y = y + i * dy[j];if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {mark[new_x][new_y] = 1;}}}
}

回到問題2上,我們想要獲取棋盤上能夠放置皇后的方法的個(gè)數(shù)以及具體的放置位置;
可以先嘗試一個(gè)一個(gè)放,當(dāng)然這放置可以按照行放,也可以按照列放(八皇后問題最終的表現(xiàn)形式就是每行只能有一個(gè),每一列只能有一個(gè))。
我們這里的放置皇后的方式都按照行放,第一行第一個(gè):

Q111
1100
1010
1001

接下來(lái)皇后的放置的規(guī)則肯定就是在不能被第一個(gè)Q影響的情況下放置了,我們這里仍然按照行進(jìn)行放置,放第二個(gè),如下紅色1則為重新放置后打入的標(biāo)記

Q111
11Q1
1111
1011

再次進(jìn)行放置,發(fā)現(xiàn)第三行已經(jīng)沒有位置可以放了,此時(shí)可以定論,最開始的第一次放置位置不合理,需要進(jìn)行回溯,回溯到第一次放置Q之前棋盤的位置,即

0000
0000
0000
0000

綜上過程我們可以知道我們算法實(shí)現(xiàn)有以下幾個(gè)點(diǎn)

  1. 按行(或者列)進(jìn)行棋盤遍歷,每一次放置一個(gè)皇后,并對(duì)皇后區(qū)域進(jìn)行打標(biāo)
  2. 以上過程需要遞歸完成,遞歸過程中發(fā)現(xiàn)無(wú)法達(dá)到N*N放置N個(gè)皇后時(shí)即終止遞歸,并回滾棋盤狀態(tài)為第一次放置皇后之前的棋盤狀態(tài)。

實(shí)現(xiàn)算法如下(文末有完整測(cè)試代碼):

/*標(biāo)記棋盤放置皇后的數(shù)組*/
void mark_queen(int x, int y, std::vector<std::vector<int> > &mark) {static const int dx[] = {0,0,-1,1,-1,1,-1,1};static const int dy[] = {-1,1,0,0,-1,-1,1,1};if (x < 0 || x > mark.size() || y < 0 || y > mark.size()) {return ;}mark[x][y] = 1;for (int i = 0;i < mark.size(); ++i) {for (int j = 0;j < 8; ++j) {int new_x = x + i * dx[j];int new_y = y + i * dy[j];if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {mark[new_x][new_y] = 1;}}}
}/*遞歸+回溯棋盤狀態(tài)*/
void generate(int k, int n, std::vector<string> &location, //用字符表示放置策略std::vector<std::vector<string>> &result, //最終的放置策略的匯總std::vector<std::vector<int> > &mark) { //保存每一次放置皇后的棋盤狀態(tài)if (k == n) { //結(jié)束條件就是發(fā)現(xiàn)當(dāng)前放置策略支持N個(gè)皇后result.push_back(location);return;}/*按行遍歷*/for (int i = 0;i < n; ++i) {/*備份初始棋盤狀態(tài)*/std::vector<std::vector<int>> tmp_mark = mark;/*放置位置就是沒有被打標(biāo)的位置,即不會(huì)被其他皇后影響的位置*/if (mark[k][i] == 0) {/*放置一個(gè)皇后,針對(duì)其進(jìn)行打標(biāo)*/mark_queen(k, i, mark);location[k][i] = 'Q';generate(k+1, n, location, result, mark);/*遞歸之后回滾到最初備份的狀態(tài)*/mark = tmp_mark;location[k][i] = '.';}}
}
/*初始化棋盤*/
std::vector<std::vector<string> > solve_N_queen(int n) {std::vector<std::vector<int> > mark;std::vector<std::vector<string> > result;std::vector<string> location;for (int i = 0;i < n; ++i) {mark.push_back(std::vector<int> ());for (int j = 0;j < n; ++j) {mark[i].push_back(0);}location.push_back("");location[i].append(n,'.');}generate(0,n,location,result,mark);return result;
}

測(cè)試代碼如下:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>/*
N皇后問題是計(jì)算機(jī)科學(xué)中最為經(jīng)典的問題之一,該問題可追溯到1848年
由國(guó)際西洋棋棋手馬克斯·貝瑟爾于提出了8皇后問題。 將N個(gè)皇后放擺放在N*N的棋盤中,互相不可攻擊,有多少種擺放方式,每種擺 放方式具體是怎樣的?類似 N = 4
那么如下輸出
solution1:
.Q..
...Q
Q...
..Q.solution2:
..Q.
Q...
...Q
.Q..
*/using namespace std;/*標(biāo)記棋盤放置皇后的數(shù)組*/
void mark_queen(int x, int y, std::vector<std::vector<int> > &mark) {static const int dx[] = {0,0,-1,1,-1,1,-1,1};static const int dy[] = {-1,1,0,0,-1,-1,1,1};if (x < 0 || x > mark.size() || y < 0 || y > mark.size()) {return ;}mark[x][y] = 1;for (int i = 0;i < mark.size(); ++i) {for (int j = 0;j < 8; ++j) {int new_x = x + i * dx[j];int new_y = y + i * dy[j];if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {mark[new_x][new_y] = 1;}}}
}void generate(int k, int n, std::vector<string> &location, std::vector<std::vector<string>> &result, std::vector<std::vector<int> > &mark) {if (k == n) {result.push_back(location);return;}for (int i = 0;i < n; ++i) {std::vector<std::vector<int>> tmp_mark = mark;if (mark[k][i] == 0) {mark_queen(k, i, mark);location[k][i] = 'Q';generate(k+1, n, location, result, mark);mark = tmp_mark;location[k][i] = '.';}}
}std::vector<std::vector<string> > solve_N_queen(int n) {std::vector<std::vector<int> > mark;std::vector<std::vector<string> > result;std::vector<string> location;for (int i = 0;i < n; ++i) {mark.push_back(std::vector<int> ());for (int j = 0;j < n; ++j) {mark[i].push_back(0);}location.push_back("");location[i].append(n,'.');}generate(0,n,location,result,mark);return result;
}int main(int argc, char const *argv[])
{int n;cin >> n;std::vector<std::vector<string>> result; result = solve_N_queen(n);cout << "num of method is " << result.size() << endl;cout << "method is " << endl;for (int i = 0; i < result.size(); ++i) {for (int j = 0;j < result[i].size(); ++j) {cout << result[i][j];cout << endl;}cout << endl;}return 0;
}

編譯:g++ -std=c++11 test.c -o test

輸出如下:

#輸入
8
#輸出
num of method is 92
method is 
Q.......
....Q...
.......Q
.....Q..
..Q.....
......Q.
.Q......
...Q....
#以下輸出較多,可自行編譯查看
...#輸入
4
#輸出
num of method is 2
method is 
.Q..
...Q
Q...
..Q...Q.
Q...
...Q
.Q..

總結(jié)

以上是生活随笔為你收集整理的递归/回溯:八皇后问题N-Queens的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。