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的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1072 排列perm

排座位&&Little Elephant And Permutation——排列dp的处理

全排列 递归方法(permutation原理

hdu 2047(状压dp)

Codeforces 691D. Swaps in Permutation

cf1208 D Restore Permutation (二分+树状数组)