zoukankan      html  css  js  c++  java
  • Kuhn-Munkres算法

    (Km)

    Kuhn-Munkres算法

    一种用于进行二分图完全匹配的算法


    (pre)技能

    匈牙利算法及增广路

    标顶

    对于图(G(Ucup V,E))。对于(xin U),定义(Lx_i)。对于(iin V)。定义(Ly_i)

    这个玩意叫做标顶,是一种人为构造的数值。用于进行二分图完全匹配

    可行标顶

    对于所有的边,假设权值是(W),方向是(x o y),则是算法执行中,恒定满足(Lx_x+Ly_ygeq W)

    相等子图

    相等子图包括(Ucup V),但只包括满足(W=Lx_x+Ly_y)的边

    若相等子图有完全匹配,则原图有完全匹配

    实现概括

    通过更改标顶,找出相等子图。


    实现具体

    扩大相等子图

    假设当前相等子图无法进行完全匹配,则至少有一个点(u),从其出发无法找到增广路

    则我们需要修改标顶,使更多的边参与进来。

    假设我们现在已经知道了一个(M),这个(M)是使其他边增加到相等子图的最小标顶修改量

    然后我们令所有的(Lx_i)减去(M),所有的(Ly_i)加上(M)

    正确性?

    假设我们现在在相等子图中在(U)中已经被匹配的点(x),则我们规定(xin A),否则(xin A')

    相似的,对于(xin V),若x已经被匹配上,则(xin B),否则(xin B')

    对于一条边((x o y),权值(代价)是(W))

    • (xin A,yin B),仍满足(Lx_x+Ly_y=W)
    • (xin A',yin B'​),则为(Lx_x+Ly_ygeq W​),即是原本就不在交替路中的的依旧不在
    • (xin A',yin B),则(Lx_x+Ly_y)增加,不会被添加进入
    • (xin A,yin B'),则(Lx_x+Ly_y)有所减少,可能会被添加
    其他

    关于

    (xin A',yin B),则(Lx_x+Ly_y)增加,不会被添加进入

    (xin A,yin B'),则(Lx_x+Ly_y)有所减少,可能会被添加

    对于上边这句,是为了保证在将一个点(x,xin U)进行匹配时,只会相应的引入(y,yin V),而不会引入(U)中的点。

    (M)如何计算?

    (M)的大小取决于没有被加到相等子图中的最大边的大小,即是(Lx_x+Ly_y-W)

    而这个我们在寻找增广路的时候就可以顺带更新。

    其他

    (M)的贪心选取保证了最大权。

    个人理解是损失最小的代价,使其可以加入到相等子图

    代码

    using std::max;
    using std::min;
    const int maxn=500;
    const int inf=0x7fffffff;
    int M[maxn][maxn];
    int m[maxn][maxn];
    int lx[maxn],ly[maxn],mins[maxn],pat[maxn];
    int S[maxn],T[maxn],tot;
    int vis[maxn];
    int n;
    bool find(int x)
    {
        S[x]=1;
        for(int i=1;i<=n;i++)
        {
            if(T[i])    continue;
            int s=lx[x]+ly[i]-m[x][i];
            if(!s)
            {
                T[i]=1;
                if(!pat[i]||find(pat[i]))
                {
                    pat[i]=x;
                    return true;
                }
            }
            else
                mins[i]=min(mins[i],s);
        }
        return false;
    }
    int KM()
    {
        for(int i=1;i<=n;i++)   lx[i]=-inf;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                lx[i]=max(lx[i],m[i][j]),ly[i]=0;
        memset(pat,0,sizeof(pat));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                mins[j]=inf;
            while(1)
            {
                memset(T,0,sizeof(T));memset(S,0,sizeof(S));
                if(find(i)) break;
                int Min=inf;
                for(int j=1;j<=n;j++)   Min=min(Min,mins[j]);
                for(int j=1;j<=n;j++)
                {
                    if(S[j])    lx[j]-=Min;
                    if(T[j])    ly[j]+=Min;
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans+=m[pat[i]][i];
        return ans;
    }
    
  • 相关阅读:
    解决UITableView中Cell重用机制导致内容出错的方法总结
    Hdu 1052 Tian Ji -- The Horse Racing
    Hdu 1009 FatMouse' Trade
    hdu 2037 今年暑假不AC
    hdu 1559 最大子矩阵
    hdu 1004 Let the Balloon Rise
    Hdu 1214 圆桌会议
    Hdu 1081 To The Max
    Hdu 2845 Beans
    Hdu 2955 Robberies 0/1背包
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/10180462.html
Copyright © 2011-2022 走看看