问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0
代码实现:
#include<iostream>
using namespace std;
int map[8][8]; //地图
int vis[8][8]; //用于做标记
int n;
int count=0;
bool cheak(int i,int j,int color) //要放皇后的坐标i,j,color:1表示黑,2表示白
{
//判断同一列
for (int k = 0; k < n; ++k) {
if (vis[k][j] == color && k != i)
return false;
}
//判断对角线
int ni=i-1;
int nj=j-1;
while(ni>=0&&nj>=0) //左上角
{
if(vis[ni][nj]==color)
return false;
ni--; nj--;
}
//右上角
ni=i-1; nj=j+1;
while(ni>=0&&nj<n)
{
if(vis[ni][nj]==color)
return false;
ni--; nj++;
}
//右下角
ni=i+1; nj=j+1;
while(ni<n&&nj<n)
{
if(vis[ni][nj]==color)
return false;
ni++; nj++;
}
//左下角
ni=i+1; nj=j-1;
while(ni<n&&nj>=0)
{
if(vis[ni][nj]==color)
return false;
ni++; nj--;
}
return true;
}
void dfsw(int k) //白皇后递归
{
if(k==n)
{
count++;
}
for(int i=0;i<n;i++) //该行有n个位置去尝试
{
if(map[k][i]==1&&vis[k][i]==0) //地图允许放且该位置没有放黑皇后
{
vis[k][i]=2; //放入白皇后
if(cheak(k,i,2))
{
dfsw(k+1); //如果满足条件,继续下一个
}
//一定要回溯
vis[k][i]=0;
}
}
}
void dfsb(int k) //递归黑皇后
{
if(k==n) {
dfsw(0); //黑皇后选择好后再递归白皇后
}
for(int i=0;i<n;i++)
{
if(map[k][i]==1) //可以放
{
vis[k][i]=1;
if(cheak(k,i,1))
{
dfsb(k+1); //满足条件进行下一轮
}
//一定要回溯
vis[k][i]=0;
}
}
}
int main()
{
cin>>n;
//处理输入
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>map[i][j];
dfsb(0); //先递归黑皇后
cout<<count<<endl;
return 0;
}