经典的八皇后问题:在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); }
小结:断断续续研究了两天各类八皇后写法,感觉自己对位运算的运用加深了一个层次,更大的收获还是知道了自己的渺小,一个原以为十分简单的八皇后都可以衍生出这么多东西,递归的非递归的,全排列搜索的,回溯法的,甚至还有广搜版本的八皇后…,学习之路果然永无止境