zoukankan      html  css  js  c++  java
  • 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
    ",++Case,fac[n]-sum);
        }
        return 0;
    }
  • 相关阅读:
    个人关于浮动的理解
    css课堂笔记(盒子模型,标准文档流,浮动,美化)
    css和html课堂笔记
    html中的行内元素和块级元素
    css简介及常用语法
    html简介及常用功能
    权重比较
    盒模型
    css常见内联和块级元素
    Vigenère密码
  • 原文地址:https://www.cnblogs.com/clno1/p/11190981.html
Copyright © 2011-2022 走看看