zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    0593. Valid Square (M)
    0832. Flipping an Image (E)
    1026. Maximum Difference Between Node and Ancestor (M)
    0563. Binary Tree Tilt (E)
    0445. Add Two Numbers II (M)
    1283. Find the Smallest Divisor Given a Threshold (M)
    C Primer Plus note9
    C Primer Plus note8
    C Primer Plus note7
    C Primer Plus note6
  • 原文地址:https://www.cnblogs.com/dzzy/p/5239704.html
Copyright © 2011-2022 走看看