zoukankan      html  css  js  c++  java
  • HDU 2853 (KM最大匹配)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853

    题目大意:二分图匹配费用流。①最大匹配②最小原配变动

    解题思路

    如果去掉第二个要求,那么就是裸KM。

    然而加上第二个要求,那么就需要一种新的建图方式。

    建图

    对于输入矩阵,每一条边,cost扩大K倍($K=n+1$)

    对于原配,每一条边cost在扩大K倍基础上+1

    KM

    统计cost时,直接把cost整除K,然后累加。

    并且Hash一下原配边的变动情况。

    扩大K倍的作用

    准确来说,K倍是为了+1而存在的。由于要优先考虑原配边,所以cost要大些。

    但是,加大的cost又要使得最后好统计真实的cost。所以选择扩大K倍,然后整除K,这样,+1会被直接舍掉。

    K=n+1是防止n=1的情况被卡姿势。

    代码

    #include "iostream"
    #include "cstdio"
    #include "cstring"
    #include "algorithm"
    using namespace std;
    #define maxn 55
    int n,m,Hash[maxn],tmp,old,K;
    int link[maxn],LX[maxn],RX[maxn],W[maxn][maxn],slack[maxn],e[maxn][maxn];
    bool S[maxn],T[maxn];
    const int inf=0x3f3f3f3f;
    bool dfs(int u)
    {
        S[u]=true;
        for(int v=1;v<=m;v++)
        {
            if(T[v]) continue;
            int t=LX[u]+RX[v]-W[u][v];
            if(!t)
            {
                T[v]=true;
                if(!link[v]||dfs(link[v]))
                {
                    link[v]=u;
                    return true;
                }
            }
            else if(t<slack[v]) slack[v]=t;
        }
        return false;
    }
    void update()
    {
        int a=inf;
        for(int i=1;i<=m;i++) //ny
           if(!T[i]&&slack[i]<a) a=slack[i];
        for(int i=1;i<=n;i++)  //nx
            if(S[i]) LX[i]-=a;
        for(int i=1;i<=m;i++) //ny
        {
            if(T[i]) RX[i]+=a;
            else slack[i]-=a;
        }
    }
    void KM()
    {
        memset(link,0,sizeof(link));
        memset(RX,0,sizeof(RX));
        for(int i=1;i<=n;i++) //nx
            for(int j=1;j<=m;j++) //ny
                LX[i]=max(LX[i],W[i][j]);
        for(int i=1;i<=n;i++) //nx
        {
            for(int j=1;j<=m;j++) //ny
                slack[j]=inf;
            while(1)
            {
                memset(S,0,sizeof(S));
                memset(T,0,sizeof(T));
                if(dfs(i)) break;
                else update();
            }
        }
        int res=0,change=0;
        for(int i=1;i<=m;i++) //ny
        {
           if(link[i])
           {
               res+=(W[link[i]][i]/K);
               if(Hash[i]!=link[i]) change++;
           }
        }
        printf("%d %d
    ",change,res-old);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%d%d",&n,&m)!=EOF)
        {
           memset(W,0,sizeof(W));
           memset(Hash,0,sizeof(Hash));
           old=0;K=n+1;
           for(int i=1;i<=n;i++)
              for(int j=1;j<=m;j++)
            {
                scanf("%d",&W[i][j]);
                W[i][j]*=K;
            }
           for(int i=1;i<=n;i++)
           {
               scanf("%d",&tmp);
               old+=(W[i][tmp]/K);
               Hash[tmp]=i;
               W[i][tmp]++;
           }
           KM();
           memset(slack,0,sizeof(slack));
           memset(LX,0,sizeof(LX));
        }
        return 0;
    }
  • 相关阅读:
    java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized...
    Spring Security 自定义 登陆 权限验证
    springboot中使用spring security,登录url就出现403错误
    RocketMQ最佳实践
    JS 中获取服务器时间的注意点
    许小年:中国经济刚入寒冬,四万亿也救不了
    RestTemplate发送GET请求
    String类的format方法的用法
    参数的打包和解包实例
    16.return 返回值
  • 原文地址:https://www.cnblogs.com/neopenx/p/4539004.html
Copyright © 2011-2022 走看看