传统弱校HFUT的蒟蒻,真相只有一个

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;
}

 

posted @ 2016-03-03 18:45  未名亚柳  阅读(202)  评论(0编辑  收藏  举报