思路:
先放黑皇后,成功后再放白皇后;
逐行放置,则皇后不会横向攻击,所以只需检查是否会纵向或斜向攻击即可;
对于黑皇后的放置,检查时:Ibq[cur] == Ibq[j] 表示当前皇后和前面的皇后在同一列,冲突;
cur - Ibq[cur] == j - Ibq[j] || cur + Ibq[cur] == j + Ibq[j] 分别表示主,副对角线皇后冲突;
代码如下:
#include<cstdio>
#include<iostream>
#define For1(i, a, b) for(int i = a; i <= b; i++)
#define For2(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
int Iwq[10], Ibq[10]; //白,黑皇后的位置
int Imap[10][10]; //棋盘
int n, tot; //皇后数,方案数
void WSearch(int cur) //白皇后的放置
{
if(cur == n) tot++; //所有皇后放置成功,方案数加1
else For1(i, 0, n-1){
if(!Imap[cur][i] || i == Ibq[cur]) continue; //此处不能放置或者已经放置黑皇后,判断下一个位置
int ok = 1;
Iwq[cur] = i; //尝试把第cur行的白皇后放在第i列
For1(j, 0, cur-1){ //检查是否和前面的皇后冲突
if(Iwq[cur] == Iwq[j] || cur - Iwq[cur] == j - Iwq[j] || cur + Iwq[cur] == j + Iwq[j]){
ok = 0; break;
}
}
if(ok) WSearch(cur + 1); //如果合法,继续放下一个
}
}
void BSearch(int cur) //黑皇后的放置
{
if(cur == n) WSearch(0); //黑皇后放置成功,开始放白皇后
else For1(i, 0, n-1){
if(!Imap[cur][i]) continue;
int ok = 1;
Ibq[cur] = i;
For1(j, 0, cur-1){
if(Ibq[cur] == Ibq[j] || cur - Ibq[cur] == j - Ibq[j] || cur + Ibq[cur] == j + Ibq[j]){
ok = 0; break;
}
}
if(ok)BSearch(cur + 1);
}
}
int main()
{
tot = 0;
scanf("%d", &n);
For1(i, 0, n-1){
For1(j, 0, n-1) scanf("%d", &Imap[i][j]);
}
BSearch(0); //先放黑皇后
printf("%d\n", tot);
return 0;
}
下面效率提高
利用二维数组 vis[][] 直接判断当前尝试的皇后所在的列和两个对角线是否已有其他皇后,主对角线 y - x 可能为负,存取时加上 n
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#define For1(i, a, b) for(int i = a; i <= b; i++)
#define For2(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
int bc[10];
int wvis[3][20], bvis[3][20];
int Imap[10][10]; //棋盘
int n, tot; //皇后数,方案数
void WSearch(int cur) //白皇后的放置
{
if(cur == n) tot++; //所有皇后放置成功,方案数加1
else For1(i, 0, n-1){
if(!wvis[0][i] && !wvis[1][cur + i] && !wvis[2][cur - i + n]
&& i != bc[cur] && Imap[cur][i]){
wvis[0][i] = wvis[1][cur + i] = wvis[2][cur - i + n] = 1;
WSearch(cur + 1);
wvis[0][i] = wvis[1][cur + i] = wvis[2][cur - i + n] = 0;
}
}
}
void BSearch(int cur) //黑皇后的放置
{
if(cur == n) WSearch(0); //黑皇后放置成功,开始放白皇后
else For1(i, 0, n-1){
if(!bvis[0][i] && !bvis[1][cur + i] && !bvis[2][cur - i + n] && Imap[cur][i]){
bc[cur] = i;
bvis[0][i] = bvis[1][cur + i] = bvis[2][cur - i + n] = 1;
BSearch(cur + 1);
bvis[0][i] = bvis[1][cur + i] = bvis[2][cur - i + n] = 0;
bc[cur] = 0;
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
tot = 0;
scanf("%d", &n);
For1(i, 0, n-1){
For1(j, 0, n-1) scanf("%d", &Imap[i][j]);
}
BSearch(0); //先放黑皇后
printf("%d\n", tot);
return 0;
}