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;
    }
  • 相关阅读:
    MATLAB 简单多边形的核
    MATLAB Moravec算子
    MATLAB Sepia Tone滤镜
    MATLAB 异或分类
    MATLAB 神经网络分类
    MATLAB 地图上画经纬度
    MATLAB 最小二乘多项式拟合
    MATLAB 对应点集配准的四元数法
    MATLAB 高斯牛顿法最优化
    MATLAB Levenberg-Marquardt法最优化
  • 原文地址:https://www.cnblogs.com/clno1/p/11190981.html
Copyright © 2011-2022 走看看