zoukankan      html  css  js  c++  java
  • HDU 5727 枚举环排列+二分图匹配/状压

    http://acm.hdu.edu.cn/showproblem.php?pid=5727


    题意:有N个白宝石,N个黑宝石,交错摆放形成环。有一些编号的黑白挨在一起总分会-1。。问题就是最多能有多少价值(起始价值n)


    思路:关键点(环形排序起始就是n-1的全排列)(标程的启发式搜索并不会。。)


    法1:二分图最大匹配。。首先枚举一下环排列。。然后我们发现把空和白宝石分成两个集合,根据不减少得分的情况建立边,最大匹配就是当前情况的最佳得分。

    法2:状压dp。。还是枚举,状态转移也不难。。但是复杂的因为每次转移有popcount(n)的接临状态。。复杂度还是比较大的。。记忆化搜索愉快的T。。。还是我太弱了。。是有神牛DP过了的。。还在学习中。。


    法1代码:

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN = 250;//点数的最大值
    const int MAXM = 2000;//边数的最大值
    struct Edge
    {
        int to,next;
    } edge[MAXM];
    int head[MAXN],tot;
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v)
    {
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    int linker[MAXN];
    bool used[MAXN];
    int uN;
    bool dfs(int u)
    {
        for(int i = head[u]; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].to;
            if(!used[v])
            {
                used[v] = true;
                if(linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    int hungary()
    {
        int res = 0;
        memset(linker,-1,sizeof(linker));
        for(int u = 0; u < uN; u++) //点的编号0~uN-1
        {
            memset(used,false,sizeof(used));
            if(dfs(u))res++;
        }
        return res;
    }
    int n,m;
    int mp[MAXN][MAXN];
    int arr[MAXN];
    
    int main(){
        while(scanf("%d%d",&n,&m)!=EOF){
            int a,b;
            if(n==0){
                cout<<"0
    ";
                continue;
            }
            memset(mp,0,sizeof(mp));
            for(int i=0;i<m;i++){
                scanf("%d%d",&b,&a);
                mp[a][b+n]=mp[b+n][a]=1;
            }
            for(int i=1;i<10;i++) arr[i]=i;
            int ans=-1;
            uN=n+n;
            do{
                init();
                for(int i=1;i<=n;i++){
                    if(i==1){
                        for(int j=1;j<=n;j++){
                            if(mp[arr[i]][j+n]==0&&mp[arr[n]][j+n]==0) addedge(i-1,j-1+n);
                        }
                    }
                    else{
                        for(int j=1;j<=n;j++){
                            if(mp[arr[i]][j+n]==0&&mp[arr[i-1]][j+n]==0) addedge(i-1,j-1+n);
                        }
                    }
                }
                ans=max(ans,hungary());
            }while(next_permutation(arr+2,arr+n+1));
            printf("%d
    ",n-ans);
        }
        return 0;
    }

  • 相关阅读:
    C# Linq 类似Scala中的map的函数
    Spark DataFrame NOT IN实现方法
    Scala scopt 命令行解析
    WPF 绑定到静态属性,可通知
    WPF GroupBox Header居中
    WPF开源项目整理(排名不分先后)
    Windows 上配置 Go 的 gRPC 编译环境
    C++20新线程 jthread 体验代码
    查找被删除但仍然占据磁盘的文件
    以Docker方式安装Redis集群
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672550.html
Copyright © 2011-2022 走看看