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;
}

浙公网安备 33010602011771号