hdu 3811 用状态压缩DP 解决看似组合数学的题目

1-n的排列

题目给出m对 a b,表示a位置放b

问你满足其中至少一对关系的总排列数

 

反过来求,先求出一对关系都不满足的排列数,在用总的排列数减去它

具体做法是对于每个位置,枚举那些不能放的数放在这个位置,不断地去更新状态数组

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef  __int64 lld;
lld fac[20];
lld dp[1<<19];
int re[20][20];
void init()
{
	fac[0]=1;
	for(int i=1;i<=17;i++)
	{
		fac[i]=fac[i-1]*i;
	}
}
int main()
{
	int i,j,k,n,m,t,ca=1,a,b;
	init();
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		memset(re,0,sizeof(re));
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&a,&b);
			a--,b--;
			re[a][b]=1;
		}
		memset(dp,0,sizeof(dp));
		dp[0]=1;
		for(i=0;i<n;i++)
		{
			for(j=(1<<n)-1;j>=0;j--)
			{
				if(!dp[j]) continue;
				for(k=0;k<n;k++)
				{
					if(j&(1<<k) || re[i][k]) continue;
					dp[j|(1<<k)]+=dp[j];
				}
			}
		}
		printf("Case %d: %I64d\n",ca++,fac[n]-dp[(1<<n)-1]);
	}
	return 0;
}

  

posted @ 2012-05-13 10:54  Because Of You  Views(310)  Comments(0Edit  收藏  举报