资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
给定一个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>
#include<cstdio>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=10010;
int main(){
int n,cnt=0;
int f[8][8];
cin>>n;
vector<int> v(n),v1(n);
for(int i=0;i<n;i++)for(int j=0;j<n;j++)cin>>f[i][j];
//back queen
for(int i=0;i<n;i++) v[i]=i; //黑皇后待抽的候选格子
do{
int flag = 1;
//每行随机抽取一个不同列、不等于零的数
for(int i=0;i<n;i++)if(f[i][v[i]]==0)flag=0;
if(flag==0) continue;
//格子不再其它格子的对角线上
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(abs(i-j)==abs(v[i]-v[j])) flag=0;
if(flag==0) break;
}
if(flag==0) break;
}
if(flag==0) continue;
for(int i=0;i<n;i++)f[i][v[i]]=0; //黑皇后占领格子
//white queen
for(int i=0;i<n;i++) v1[i]=i; //白皇后待抽的候选格子
do{
int flag1 = 1;
//每行随机抽取一个不同列、不等于零的数
for(int i=0;i<n;i++)if(f[i][v1[i]]==0) flag1=0;
if(flag1==0) continue;
//格子不再其它格子的对角线上
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(abs(i-j)==abs(v1[i]-v1[j])) flag1=0;
if(flag1==0) break;
}
if(flag1==0) break;
}
if(flag1==0) continue;
cnt++; //白皇后与黑皇后选的组合可以放完n个白皇后与n个黑皇后,即可用放法+1
}while(next_permutation(v1.begin(),v1.end())); //令容器v1的元素实现各种排列组合
for(int i=0;i<n;i++)f[i][v[i]] = 1; //还原被更改的格子
}while(next_permutation(v.begin(),v.end())); //将容器v的元素顺序打乱,以实现各种排列组合
cout<<cnt<<endl;
return 0;
}
解题思路
通过STL库函数,列出黑皇后...每行每列各抽取一格...的所有种可能,抽取的格子中每个格子的数都不能为零且所抽取的格子不处于同一对角线 ,之后黑皇后占领格子(f[i][v[i]]=0)。同理,白皇后也一样,若能成功抽出格子则可用放法+1。
/*————————————————
版权声明:本文为CSDN博主「苏格拉没底——」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_924485343/article/details/108541197*/
文章注释即解题思路为本人所写,如出现错误,希望大家可以指出;
本人小白一枚,望大佬能够点评一二;
感谢阅读!