在学习2n皇后之前,我们应该认识一下n皇后问题:
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
输入样例:
1
8
5
0
输出样例:
1
92
10
可以这么理解,以4皇后为例子:
现在剩下的问题是通过一些必要的操作使得这个算法的运算效率变高,这就是剪枝;
可以这样认为,设起始第一行第一列放皇后并设其坐标是(0,0),设放皇后的坐标为(i,j),为了避免重复,新皇后的坐标是(r,c),
可以看到:为了避免同列j!=c;
然后同行我们可以不用比较(因为我们是遵循着每一行只放一个皇后的原则摆放);
假设从放皇后的坐标到新皇后的坐标斜着走a步,那有新皇后坐标相对于皇后坐标来讲的话就有左上(i-r,j-c),左下(i-a,j+a),右下(i+a,j+a),右上(i+a,j-a),无论如何,都是|i-r|=|j-c|;
那为了满足题目要求就有|i-r|!=|j-c|;
题目就明确了,代码如下:
#include<bits/stdc++.h> using namespace std; int col[12]={0}; //col数组用于存放第i行第col[i]列放置皇后。 int n,tot = 0; //设置全局变量,即可不用投值,直接调用 bool check(int r,int c){ //判断新皇后是否和放好的皇后发生冲突。 for(int i=0;i<r;i++){ //这里不需要判断是否同行,因为我们设置的每行只投放一个皇后,所以不需要判断,只判断是否同列或者同斜线即可。 if((col[i]==c)||(abs(col[i]-c)==abs(i-r)))return false; } return true; } void dfs(int r){ if(r==n){ //因为从0开始,当行数r达到n时,表示已经完成了 tot++; return ; } for(int c=0;c<n;c++){ if(check(r,c)){ //判断是否可以放置,可以便放置,否则剪枝。 col[r]=c; dfs(r+1); //继续放置下一行的新皇后 } } } int main(){ int ans[12]={0}; for(n=0;n<=10;n++){ //对n皇后进行打表,然后结果存入ans数组 memset(col,0,sizeof(col)); //每次要进行初始化 tot=0; dfs(0); //DFS ans[n]=tot; //存放 } while(cin >> n){ if(n==0)return 0; cout << ans[n] << endl; } return 0; }
并且附上一个讲的很好的视频链接:https://www.bilibili.com/video/BV1bK4y1n7iq?spm_id_from=333.999.0.0
接下来就是2n皇后问题了,大体思路和n皇后问题差不多了,不同之处是需要判断能不能放皇后,那我们可以如下解决:
在放完了黑皇后(先放黑)在处理白皇后,其中如果没放完的话判断能不能放皇后这样一个问题,然后对于白皇后我们除了判断能不能放皇后的同时也要判断那个位置是不是被黑皇后占了
代码如下:
#include<bits/stdc++.h> using namespace std; const int maxn = 10; int n; int mapqueen[maxn][maxn]; //能不能放皇后 int whqueen[maxn]={0}; //白皇后位置 int blqueen[maxn]={0}; //黑皇后位置 int ans; bool checkbl(int step,int c) { for(int i=1;i<step;i++) { if(blqueen[i]==c||(abs(blqueen[i]-c)==abs(i-step))) return false; } return true; } bool checkwh(int step,int c) { for(int i=1;i<step;i++) { if(whqueen[i]==c||(abs(whqueen[i]-c)==abs(i-step))) return false; } return true; } void dfs_white(int step) { if(step==n+1) { ans++; } for(int c=1;c<=n;c++) { if(blqueen[step]==c) continue; if(mapqueen[step][c]==0) continue; whqueen[step]=c; if(checkwh(step,c)) { dfs_white(step+1); } } } void dfs_black(int step) { if(step==n+1) { dfs_white(1); } for(int c=1;c<=n;c++) { if(mapqueen[step][c]==0)//第step行第i列是否放了皇后的条件 continue; blqueen[step]=c;//在第step行第i列放黑皇后 if(checkbl(step,c)) { dfs_black(step+1);//进入下一层 } } } int main() { cin>>n; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&mapqueen[i][j]); } } dfs_black(1);//从第一行开始搜黑皇后 printf("%d\n",ans); return 0; }