1. 程式人生 > >經典演算法 | n皇后問題易理解演算法和最高效率演算法分析

經典演算法 | n皇后問題易理解演算法和最高效率演算法分析

經典演算法值n後問題,

這題題給你一個n*n的棋盤,問你放置n個皇后共有多少種不用的放置方法,


在任意一個皇后所在位置的水平、豎直、以及45度斜線上都不能出現皇后的棋子

這是一個典型的回溯法框架,並且也是很簡單的一個回溯法框架,比這個更簡單的就只有字串全排列問題了。

這題使用深度優先遍歷的回溯法解決,每一行只放一個皇后,每一列只放一個皇后,如何判斷某個皇后是否和前面已經放置的皇后斜線衝突呢,使用abs(a-b)==abs(c-d),ac,bd分別為參與判斷的兩個皇后的橫縱座標,只要這個等式成立則這兩個皇后一定斜線衝突

使用一個數組儲存,陣列的下標表示行數,陣列儲存的值表示列數,通過交換陣列每個值的位置就能實現n皇后問題的全排列的尋找

n皇后問題簡單易懂演算法框架:

大體思路是對於陣列list的第t個位置,表示第t層,其值表示這一行的皇后所在的列數,這裡假設取list[t]為這一行的列數,當取定這一行的列數後把list[t]和list[a]交換位置,那麼t+1~n(n為list長度)就是表示下一層皇后可供選擇的列數

如何判斷list[a]是否可取呢,只需要判斷llist[a]和前面已經確定的皇后位置是否斜線衝突就行了,也就是abs(a-b)==abs(c-d),ac,bd分別為參與判斷的兩個皇后的橫縱座標

public:
bool check(vector<int> list, int t)
{
      for(int i = 0; i < t; i++)
      {
            if(abs(i - t) == abs(list[i] - list[t])) return false;
      }
      returntrue;
}
void p(vector<int> list, int t,int& count)
{
      if(t == list.size()) {
            count++;return; }
      for(int i = t; i < list.size(); i++)
      {
            swap(list[i],list[t]);
            if(check(list, t)) p(list, t+1, count);
            swap(list[i],list[t]);
      }
}
int totalNQueens(int n) {
      vector<int>list(n, 0); int count = 0;
      for(int i = 0; i < list.size(); list[i] = i,i++);
      p(list,0, count);
      returncount;
}
};

下面是n皇后問題的最高效率演算法:

基本思路跟上面那一個很想,不同的地方是當確定一個皇后的位置後,假設確定位置為t,則將位置t行列之和對應的flag位置設定為1,將t行列之差對應的flag位置設定為1,將t列數相同的flag設定為1,之後再找皇后的時候只需要判斷flag[i]&& !flag[row + i +n] && !flag[4* n + row - i])就行了,flag[4*n +row - i])前面加上一個4*n是因為行列之和最大為4*n

class Solution {
public:
      inttotalNQueens(int n) {
            boolflag[5 * n] ={ false };
            int num= 0;
            dfs(num, flag, 0, n);
            returnnum;
      }
      void dfs(int& num, bool* flag, int row, int n) {
            if (row == n) {
                  ++num;
                  return;
            }
            for (int i = 0; i<n; i++) {
                  if(!flag[i]&& !flag[row + i + n] && !flag[4 * n + row - i]) {
                       flag[i] = 1;
                       flag[row + i + n] = 1;
                       flag[4 * n + row - i] = 1;
                       dfs(num, flag, row + 1, n);
                       flag[i] = 0;
                       flag[row + i + n] = 0;
                       flag[4 * n + row - i] = 0;
                  }
            }
      }
};