n皇后問題[分支限界法]


問題:
  如何能夠在 n×n 的國際象棋棋盤上放置八個皇后,使得任何一個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。

分析:
  我們可以用一串數字來表示問題的解,比如[2,4,1,3] 表示 4×4 棋盤的4皇后問題的解,第一行的棋子擺在第2列;第二行的棋子擺在第4列,依此類推
  這里將用回溯法進行解題,可以看出,某一行的棋子擺了之后,棋子的那一列肯定不能再擺其他的棋子了,

  所以解[x,x,x,……,x] 一定是 1-n 的一個全排列,

  所以這里的解空間樹我們選擇排列樹。


思路:
  既然已經確定了要用排列樹來作為問題的解空間樹,接下來要確定的就是剪枝函數了。

  剪枝函數只要從已經擺好的棋子的第一個開始遍歷,依此判斷下面的棋子是否在其攻擊范圍內即可,

  因為我們之前沒有在同一行擺多個棋子,也沒有在同一列擺多個棋子,所以只要判斷其他棋子是否在其斜線上的攻擊范圍即可,比如

      

  第一行的棋子擺在第3列上,只要沿圖中方向判斷即可

    

for (int i = 1; i <= n-1; i++) { for (int j = i + 1; j <= n; j++) { int left = -(j - i);//向左的斜線
            int right = (j - i);//向右的斜線
            if (pieces[j] == pieces[i] + left||pieces[j] == pieces[i] + right) {//第i行皇后和第j行皇后會互相攻擊
                return false; } } }

代碼:

  這樣擺好所有棋子后即可輸出,代碼如下:

  

#include<iostream> #include<ctime>
using namespace std; bool isOK(int n, int pieces[]) { //剪枝函數 //判斷當前狀態是否合理,即皇后會不會互相攻擊
    for (int i = 1; i <= n-1; i++) { for (int j = i + 1; j <= n; j++) { int left = -(j - i);//向左的斜線
            int right = (j - i);//向右的斜線
            if (pieces[j] == pieces[i] + left||pieces[j] == pieces[i] + right) {//第i行皇后和第j行皇后會互相攻擊
                return false; } } } //所有皇后都不會互相攻擊
    return true; } void swap(int &a, int &b) { int t = a; a = b; b = t; } void nQueen(int n, int t, int pieces[]) { if (t > n) { for (int i = 1; i <= n; i++) { for (int j = 1; j < pieces[i]; j++) cout << "- "; cout << pieces[i]<<" "; for (int j = pieces[i] + 1; j <= n; j++) cout << "- "; cout << endl; } cout << endl; } else { for (int i = t; i <= n; i++) { swap(pieces[t], pieces[i]); if (isOK(t, pieces)) { nQueen(n, t + 1, pieces); } swap(pieces[t], pieces[i]); } } } void main() { int n; cin >> n; int *pieces = new int[n + 1]; for (int i = 1; i <= n; i++) { pieces[i] = i; } nQueen(n, 1, pieces); cout << "OK" << endl; system("pause"); }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM