經典的八皇后問題:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
很早就接觸過八皇后問題,最近數據結構作業中又看到了這個題目,仔細研究了一波網上諸位大牛的博客,發現這個問題居然有這么多有趣的優化。
1.經典的回溯遞歸解法:
#include<stdio.h> #include<iostream> using namespace std;
//dfs,每行只能放一個元素,遍歷每行的每個位置,用一個一維數組記錄,最后檢查是否符合要求 int ans; int vis[10]; int abs(int x){ return x > 0 ? x : -x; } bool check(int r,int c){ for(int i = 1;i<r;i++){ if(vis[i] == c) return false; if(vis[i] - c == r - i || vis[i] - c == i - r) return false; } return true; } void dfs(int r){ if(r > 8){ ans++; return; } for(int i = 1;i<=8;i++){ if(check(r,i)){ vis[r] = i; dfs(r+1); vis[r] = 0; } } } main(){ dfs(1); cout<<ans<<endl; }
2.對角線檢查優化
/*用三個數組記錄列,左對角線,右對角線信息,每次判斷該位置是否符合要求,只在符合要求位置放置元素。*/ #include <iostream> using namespace std; const int maxn=105; const int mo=100; typedef long long ll; int a[maxn],n = 8,ans=0; bool b[maxn],c[maxn],d[maxn]; void sou(int x){ if(x > n){ ans++; return; } for(int i = 1;i <= n;i++)if(!(b[i] || c[x+i] || d[x-i+n])){ b[i] =c [x+i]=d[x-i+n]=true; a[x] = i; sou(x+1); b[i] =c [x+i] = d[x-i+n]=false; } } int main(){ sou(1); cout<<ans; }
3.位運算:
//算法思想與上一相同,改用三個int來存儲信息,采用位運算提取合適位置 #include<iostream> #include<stdio.h> using namespace std; int board; int n; int ans = 0; void n_queen(int col,int ld,int rd){ if(col == board){ ans++; return; } int pos = board & (~(col | ld | rd)); while(pos){ int p = pos & (-pos); pos = pos - p; n_queen(col | p , (ld | p) << 1,(rd | p) >> 1); } } int main(){ cin>>n; board = (1 << n) - 1; n_queen(0,0,0); cout<<ans<<endl; }
4.十行內的八皇后...
https://www.zhihu.com/question/28543312
對知乎上各路大大的炫技佩服的五體投地,更改了一下上一代碼,勉強也達到了十行的要求。。。
#include<iostream> int n_queen(int col,int ld,int rd,int board){ if(col == board) return 1; int tot = 0; for(int pos = board & (~(col | ld | rd)); pos != 0;pos -= (pos & (-pos))) tot+=n_queen(col | (pos & (-pos)) , (ld | (pos & (-pos))) << 1,(rd | (pos & (-pos))) >> 1,board); return tot; } int main(){ std::cout<<n_queen(0,0,0,(1<<8)-1); }
小結:斷斷續續研究了兩天各類八皇后寫法,感覺自己對位運算的運用加深了一個層次,更大的收獲還是知道了自己的渺小,一個原以為十分簡單的八皇后都可以衍生出這么多東西,遞歸的非遞歸的,全排列搜索的,回溯法的,甚至還有廣搜版本的八皇后...,學習之路果然永無止境