n皇后问题
题目描述:
众所不知, rly现在不会玩国际象棋。但是,作为一个OIer, rly当然做过八
皇后问题。这里再啰嗦几句,皇后可以攻击到同行同列同对角线,在n*n的方格中摆n个皇后使其互不攻击到,求不同的解的数量,这就是经典的n皇后问题。
现在问题推广到n皇后问题,这个问题对于你而言实在是小菜一叠。但因为上一次rly把棋盘弄破了,又拿不出新的,所以rly打算难一点点,问题就是破棋盘上的n皇后问题。他想知道……(你们懂的)。
棋子都是相同的。
输入说明:
一行,一个正整数N。
接下来N行,每行N个数,要么为0,表示没坏,要么1,表示坏了。
输出说明:
一行,输出不同的解的数量。
样例输入:
4
1 0 1 1
1 1 1 0
0 1 1 1
1 1 0 1
样例输出:
1
数据范围:
对于40%的数据, N<=13。
对于100%的数据, N<=16。
其中有30%的数据,棋盘没有破(你可以认为rly又去买了一个新的)。
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=30;
int n,ans,a[maxn];
void dfs(int t,int l,int x,int y)//当前行t的状态,x用二进制表示一条对角线,y用二进制表示另一条对角线的状态
{
if(t==n+1)
{
ans++;
return;
}
int s=((1<<n)-1)&(~(a[t]|l|x|y));
/*
S存的能放的位置 先把行 列 对角线或起来现在1表示已经放过
然后取反后1代表没放过能放得到能放的
*/
while(s)
{
int z=s&(-s);//lowbit找能放的位置-->即找1
dfs(t+1,l+z,(z+x)<<1,(y+z)>>1);//l,x,y能更新放的位置(对角线到下一行会移一列)
s-=z;
}
}
int main()
{
freopen("queen.in","r",stdin);
freopen("queen.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
if(x) a[i]+=(1<<j-1);
}
}
dfs(1,0,0,0);
cout<<ans;
fclose(stdin);fclose(stdout);
return 0;
}