回溯法經典—n-皇后問題

n-皇后問題是回溯法中經典中的經典,其基本問題描述是:在一個nxn的格子中放n個皇后,使得每個皇后不能相互攻擊,任意兩個皇后能夠互相攻擊的條件是他們在同一條對角線或者同一行或者同一列上

問題可以轉換爲從第0行開始放置皇后一直放到n-1行,使得每一行在放置皇后的同時,不能與前面的皇后相互攻擊

即列,對角線不衝突即可(行肯定不衝突)

僞代碼描述

search(cur) { //表示開始放置第cur個皇后,當然行數爲cur,放置皇后的時候主要是確定cur的列
1.如果所有皇后都放置完畢,則打印出來
2.嘗試將第cur個皇后放在第j列(0<=j<=n-1),如果放在某一列j使得該位置與前面cur-1個皇后不衝突,那麼這個位置是合理的
  可以將其放在該位置,並且在這種放置方案下繼續放置第cur+1個皇后
}


c++代碼描述

#include <iostream>
using namespace std;

void search(int cur, int c[], int n) {
  if (cur == n) {
    for (int i = 0; i < n; i++){
      cout << "               ";
      for (int j = 0; j < n; j++)
        if (j == c[i])
          cout << "Q ";
        else
          cout << "* ";
      cout << endl;
    }
    cout << endl;
  } else {
    for (int j = 0; j < n; j++) {
      //先檢查是否和前面cur-1個皇后有衝突
      int ok = 1;
      c[cur] = j; //嘗試把cur放到第j列
      //檢查(cur, c[cur]) 與(i, c[i])是否不能攻擊
      for (int i = 0; i < cur; i++) {
        if (c[cur] == c[i] || cur - c[cur] == i - c[i] || cur + c[cur] == i + c[i]) {
          ok = 0;
          break;
        }
      }
      if (ok) {
        search(cur+1, c, n);
      }
    }
  }
}

int main() {
  int c[4];
  search(0, c, 8);
  return 0;
}

程序的效率還可以提高,主要是將一個nxn的方格的對角線進行編號,首先,我們應該注意到,放置任意一個皇后之後,該皇后所在的列,主對角線,副對角線都不能放置任何皇后了,上面的算法是用遍歷來查詢正確的位置,而這裏,我們每放置一個皇后之後,可以給對應的主對角線,副對角線加上標誌,關於主對角線,副對角線,可以用下面一幅圖來說明


所以,我們可以用一個3x(2n)的數組來標誌對應的列,主對角線,副對角線上是否已經有皇后

vis[0][index] = 1標示第index上已經有皇后

vis[1][index] = 1標示第index條主對角線上已經有皇后

vis[2][index] = 1標示第index條副對角線上已經有了皇后

那麼我們簡單推理一下格子(x, y)使得

vis[0][y] = 1

vis[1][y-x+n] = 1 //爲防止出現負數下標,所以每一個對應的編號加上n

vis[1][y+x] = 1


最後,我們用c++代碼來實現

#include <iostream>
using namespace std;
int n = 4;
int v[2][8];
int c[4];
void search(int cur) {
  if (cur == n) {
    for (int i = 0; i < n; i++){
      cout << "               ";
      for (int j = 0; j < n; j++)
        if (j == c[i])
          cout << "Q ";
        else
          cout << "* ";
      cout << endl;
    }
    cout << endl;
  } else {
    for (int j = 0; j < n; j++) {
      if (!v[0][j] && !v[1][j-cur+n] && !v[2][cur+j]) {
        c[cur] = j;
        v[0][j] = v[1][j-cur+n] = v[2][cur+j] = 1;
        search(cur+1);
        v[0][j] = v[1][j-cur+n] = v[2][cur+j] = 0;
      }
    }
  }
}


int main() {
  search(0);
  return 0;
}


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