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代表不能放)

状压dp

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]);//输出
} 

谢谢