“2n皇后”问题本质上还是 用 dfs 写“8皇后”问题。
先确定黑皇后的排列,再确定白皇后的排列。
此代码特色:
1)用一维数组posb[maxn]、posw[maxn]即可表示黑白皇后的摆放。
eg. posb[2]=1 表示黑皇后在第二行第一列放一枚。
2)if( posw[i] == posw[cur] || abs(i-cur) == abs(posw[i]-posw[cur]))
这个是本程序的关键代码。可判断是否有同列(不可能同行),左右斜对角线的皇后。
完整代码:
#include<cmath>
#include<iostream>
using namespace std;
const int maxn = 10;
int n;
int map_Q[maxn][maxn];
int posb[maxn]={0};
int posw[maxn]={0};
int ans;
bool checkw( int cur) //检查函数
{
for( int i = 1; i < cur; i++)
if( posw[i] == posw[cur] || abs(i-cur) == abs(posw[i]-posw[cur]))
//关键!关键!关键!
// 通过 i 来循环 1~ cur-1层
// posb[i] == posb[cur] 控制不在同一列
//本身不可能在同一行
// abs(i-cur) == abs(posb[i]-posb[cur]) 控制了不在同 左右斜对角线!
{
return false;
}
return true;
}
bool checkb( int cur) //检查函数
{
for( int i = 1; i < cur; i++)
if( posb[i] == posb[cur] || abs(i-cur) == abs(posb[i]-posb[cur]))
//关键!关键!关键!
// 通过 i 来循环 1~ cur-1层
// posb[i] == posb[cur] 控制不在同一列
//本身不可能在同一行
// abs(i-cur) == abs(posb[i]-posb[cur]) 控制了不在同 左右斜对角线!
{
return false;
}
return true;
}
void dfs_white( int cur)
{
if( cur == n+1) //白皇后也全部放完,次数+1
{
ans++;
}
for( int i = 1; i <= n; i++)
{
if( posb[cur] == i) //表示第cur列的第i行位置已经被黑皇后占用,
continue; //结束当前循环,i+1
if( map_Q[cur][i] == 0) //再判断前提条件是否成立
continue;
posw[cur] = i; //尝试把第cur列的白皇后放在第i行上
if( checkw(cur)) //判断能否放置白皇后
dfs_white(cur+1); //递归
}
}
void dfs_black( int cur)
{
if( cur == n+1) //当黑皇后处理完时,再处理白皇后,从第一行开始放
{
dfs_white(1);
}
for( int i = 1; i <= n; i++) //表示 放第 cur行的 第 i列
{
if( map_Q[cur][i] == 0) //如果第cur列第i行满足放皇后的前提条件即 mp[cur][i] == 1
continue; //如果不满足,则结束当前循环,进行下一次循环即i+1。
posb[cur] = i; //就尝试把第cur列的黑皇后放在第i行上
if( checkb(cur)) //然后判断该尝试是否成立,如成立,则进行递归,如不成立,则尝试把当前列的黑皇后放在下一行(i+1行)上。
dfs_black(cur+1); //递归
}
}
int main()
{
cin>>n;
for( int i = 1; i <= n; i++) //定义棋盘
for( int j = 1; j <= n; j++)
cin>>map_Q[i][j];
ans = 0;
dfs_black(1); //先把黑皇后放在第一列
cout<<ans<<endl;
return 0;
}