车
Description
在n*n(n≤20)的方格棋盘上放置n个车(可以攻击所在行、列),有些格子不能放,求使它们不能互相攻击的方案总数。
Input
第一行为棋盘的大小n
第二行为障碍的数量m
第三行到第m+3为m个障碍
Output
总数
Sample Input
4
2
1 1
2 2
Sample Output
14
解题思路
我们可以设f[i][j]为当前第i,j这个位置答案方案数,优化就是状压DP
状压DP就是降维,把其中一维用二进制表示,转换为十进制存到数组里
我们用a数组表示这一行障碍的状态,则它的转移就是
a[x]+=cf[y−1]
其中cf代表二的次方(注:我们这里是从右到左看)
转移:
首先我们要枚举它所有的状态个数,即cf[n]−1
我们要考虑当前的障碍状压,所以我们要用一个a来记录当前的行数,然后我们就得出这样一个转移方式
for(long long i=1;i<=m;i++)
a[x[i]]+=cf[y[i]-1];
最后呈上AC代码(0代表能放,1代表不能放)
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
long long n,m,sum,a[10000005],x[10000005],y[10000005],f[10000005]={
1},cf[10000005];//定义大一点
long long lowbit(long long x){
return x&(-x);}//求0的个数
int main()
{
scanf("%lld%d",&n,&m);
for(long long i=1;i<=m;i++)
scanf("%lld%lld",&x[i],&y[i]);
cf[0]=1;//2的次方
for(long long i=1;i<=n;i++)//算2的次方
cf[i]=cf[i-1]*2;
for(long long i=1;i<=m;i++)
a[x[i]]+=cf[y[i]-1];
for(long long i=1;i<=cf[n]-1;i++)//枚举
{
sum=0;
for(long long j=i;j;j-=lowbit(j))sum++;//累加0的个数
for(long long j=i&~a[sum];j;j-=lowbit(j))//枚举0的个数
f[i]+=f[i^lowbit(j)];//累加
}
printf("%lld",f[cf[n]-1]);//输出
}