问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
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
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0
这个题的思路是,先用回溯法找到n皇后问题的可行的序列,然后从这些序列中找到完全不同的两组序列(第一组为黑皇后位置,第二组为白皇后位置),找到一个sum++,当然黑白皇后可以互换位置,故sum最后还要乘以2.
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int map[10][10];//棋盘序列
int x[10];//(i,x[i])表示第i行第x[i]列
int sum=0,k=0;//sum用来计次数,k用来记录可行序列
int seq[94][10];//可行序列,经计算8皇后问题,最多有92个可行序列
bool OK(int k) //判断第k行各位置能否放上皇后
{
if(map[k][x[k]]==0)
return false;
for(int i=1;i<k;i++)
if(x[i]==x[k]||abs(i-k)==abs(x[i]-x[k]))
return false;
return true;
}
void backtrack(int t,int n)//回溯
{
if(t>n)
{
for(int i=1;i<=n;i++)
seq[k][i]=x[i]; //将可行序列记录
k++;
}
else
{
for(int i=1;i<=n;i++)
{
x[t]=i;
if(OK(t))
backtrack(t+1,n);
}
}
}
bool isdif(int a[],int b[],int n)//判断两序列是否完全不同
{
for(int i=1;i<=n;i++)
if(a[i]==b[i])
return false;
return true;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cin>>map[i][j];
}
backtrack(1,n);
for(int i=0;i<k;i++)
for(int j=i+1;j<k;j++)
if(isdif(seq[i],seq[j],n))
sum++;
cout<<sum*2<<endl;
return 0;
}