• HDU 2853 最大匹配&KM模板


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

    这道题初看了没有思路,一直想的用网络流如何解决

    参考了潘大神牌题解才懂的

    最大匹配问题KM

    还需要一些技巧来解决最小变动,

    做法是:把原先的邻接矩阵每个数扩大k倍(k>n)

    为了突出原先的选择,也就是同等情况下优先选择原来的方案

    给原来的方案对应矩阵内的数据+1

    那么

    最终得出的最大匹配值/k=真实的最大匹配

    最终得出的最大匹配值%k=原来的方案采用了几个

    这里的KM留下来做模板

    /*
    二分图最佳匹配 (kuhn munkras 算法 O(m*m*n)).
    邻接矩阵形式 。  返回最佳匹配值,传入二分图大小m,n
    邻接矩阵 mat ,表示权,match1,match2返回一个最佳匹配,为匹配顶点的match值为-1,
    一定注意m<=n,否则循环无法终止,最小权匹配可将全职取相反数。
    初始化:  for(i=0;i<MAXN;i++)
                 for(j=0;j<MAXN;j++) mat[i][j]=-inf;
    对于存在的边:mat[i][j]=val;//注意不能负值
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 55
    #define inf 1000000000
    #define _clr(x) memset(x,-1,sizeof(int)*maxn)
    using namespace std;
    int donser[maxn][maxn];
    int match1[maxn],match2[maxn];
    int km(int m,int n,int mat[][maxn],int *match1,int *match2)
    {
            int s[maxn],t[maxn],ak[maxn],ac[maxn];
        int p,q,i,j,k,ret=0;
        for(i=0;i<m;i++)
        {
            ak[i]=-inf;
            for(j=0;j<n;j++)
                ak[i]=mat[i][j]>ak[i]?mat[i][j]:ak[i];
            if(ak[i]==-inf)  return -1;
        } 
        for(i=0;i<n;i++)
            ac[i]=0;
        _clr(match1);
        _clr(match2);
        for(i=0;i<m;i++)
        {
            _clr(t);
            p=0;q=0;
            for(s[0]=i;p<=q&&match1[i]<0;p++)
            {
                for(k=s[p],j=0;j<n&&match1[i]<0;j++)
                {
                    if(ak[k]+ac[j]==mat[k][j]&&t[j]<0)
                    {
                        s[++q]=match2[j];
                        t[j]=k;
                        if(s[q]<0)
                        {
                            for(p=j;p>=0;j=p)
                            {
                                match2[j]=k=t[j];
                                p=match1[k];
                                match1[k]=j;
                            }    
                        }    
                    }    
                }    
            } 
            if(match1[i]<0)
            {
                i--;
                p=inf;
                for(k=0;k<=q;k++)
                {
                    for(j=0;j<n;j++)
                    {
                        if(t[j]<0&&ak[s[k]]+ac[j]-mat[s[k]][j]<p)
                           p=ak[s[k]]+ac[j]-mat[s[k]][j];
                    }    
                }  
                for(j=0;j<n;j++)
                   ac[j]+=t[j]<0?0:p;
                for(k=0;k<=q;k++)
                   ak[s[k]]-=p;  
            }       
        } 
        for(i=0;i<m;i++)
            ret+=mat[i][match1[i]];
        return ret;      
    }
    int main()
    {
        int n,m,i,j;
        while(~scanf("%d%d",&n,&m))
        {
            int k=n+1,t,num=0;
            for(i=0;i<n;i++)
            {
                for(j=0;j<m;j++)
                {
                    scanf("%d",&t);
                    donser[i][j]=t*k;
                }
            }
            for(i=0;i<n;i++)
            {
                scanf("%d",&t);
                //cout<<i<<" "<<t-1<<" "<<donser[i][t-1]<<endl;
                num+=donser[i][t-1]/k;
                donser[i][t-1]+=1;
            }
            int kk=km(n,m,donser,match1,match2);
            cout<<n-kk%k<<" "<<kk/k-num<<endl;
            memset(donser,0,sizeof(donser));
        }
        return 0;
    }
  • 相关阅读:
    青岛理工大学邀请赛总结
    HDU 1232 并查集/dfs
    HDU 1556
    HDU 5228
    POJ1011
    线段树(数组实现)
    NOIP2008 普及组T1 ISBN号码 解题报告-S.B.S.
    NOIP2008 普及组T4 立体图 解题报告-S.B.S.(施工未完成)
    noip2008普及组4题题解-rLq
    noip2008普及组3题题解-rLq
  • 原文地址:https://www.cnblogs.com/dzzy/p/5239704.html
Copyright © 2020-2023  润新知