HDU-3811 Permutation 状压DP
Posted clno1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU-3811 Permutation 状压DP相关的知识,希望对你有一定的参考价值。
题意:求满足下面条件的n的排列个数:条件为给出m个点对<x,y> 只要这个排列满足至少一个位置p[x]=y即算满足条件。
解法:这道题不算难应该要想出来的,结果没想出来自己还是蒟蒻呀qwq。我们观察满足一个p[x]=y即可以,但是这样很难统计,发现它的反面条件就是不满足任何一个p[x]=y。于是我们从这个入手用状压DP求出不满足条件数量然后用总数n!减去即是答案。
设dp[i][state]代表长度为i的排列使用数字情况state的不完美数量
用填表法DP,写出状态转移方程 dp[i+1][state|(1<<k)]+=dp[i][state] (如果state状态下i位置能填数字k)。 然后照着这个DP方程写就可以了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; int n,m,g[20][20]; LL fac[20],dp[1<<18]; //dp[i][state]代表长度为i的排列使用数字情况state的不完美数量 int main() int T,Case=0; cin>>T; fac[0]=1; for (int i=1;i<=17;i++) fac[i]=fac[i-1]*i; while (T--) scanf("%d%d",&n,&m); int ALL=(1<<n)-1; memset(g,0,sizeof(g)); for (int i=1;i<=m;i++) int x,y; scanf("%d%d",&x,&y); g[x][y]=1; //x位置不能y memset(dp,0,sizeof(dp)); dp[0]=1; LL sum=0; for (int i=1;i<=n;i++) //长度i:现在填到位置i for (int j=ALL;j>=0;j--) //数字使用情况state for (int k=1;k<=n;k++) //这一位置填数字k if ((1<<(k-1))&j) continue; if (g[i][k]) continue; dp[(1<<(k-1))|j]+=dp[j]; dp[j]=0; for (int i=0;i<=ALL;i++) sum+=dp[i]; printf("Case %d: %lld\n",++Case,fac[n]-sum); return 0;
以上是关于HDU-3811 Permutation 状压DP的主要内容,如果未能解决你的问题,请参考以下文章
排座位&&Little Elephant And Permutation——排列dp的处理