题目描述:
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入:
输入的第一行为一个整数n,表示棋盘的大小。 n小于等于8
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出:
输出一个整数,表示总共有多少种放法。
样例输入:
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出:
2
思路:
皇后问题dfs即可解决,这里就是两个皇后叠加
我们用vis[]来标记行
用a[dep][i]表示如果放了皇后,那么所有横行都会被标记
左斜线的规律是同一条斜线的格子,行列之和是相等
所以x1[dep+i]标记我们的左斜线
右斜线的规律是每个格子行和列之差是相等
但是有特殊情况
举个例子:
比如(1,6)的差是-5,但是我们选择+n来标记,这样数组的下标就不会为负
所以y1[dep-i+n]来标记我们的右斜线
同理第二个皇后也是一样
最后注意我们搜索完一行以后一定要回溯!!!(即vis[]=0,a[][]=1,x[]=0,y[]=0)
#include<bits/stdc++.h>
int a[9][9],vis1[9],vis2[9],cnt,n;
int x1[19],x2[19],y1[19],y2[19];
void DFS(int dep)
{
if(dep==n+1) { cnt++; return ;}
for(int i=1;i<=n;i++)
{
if(!vis1[i] && a[dep][i] && !x1[dep+i] && !y1[dep-i+n])
{
vis1[i]=1; a[dep][i]=0; x1[dep+i]=1; y1[dep-i+n]=1;
for(int j=1;j<=n;j++)
{
if(!vis2[j] && a[dep][j] && !x2[dep+j] && !y2[dep-j+n])
{
vis2[j]=1;a[dep][j]=0; x2[dep+j]=1; y2[dep-j+n]=1;
DFS(dep+1);
vis2[j]=0;a[dep][j]=1; x2[dep+j]=0; y2[dep-j+n]=0;
}
}
vis1[i]=0; a[dep][i]=1; x1[dep+i]=0; y1[dep-i+n]=0;
}
}
}
int main(void)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
DFS(1);
printf("%d",cnt);
return 0;
}