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