• KM算法


    啊呜啊呜,看来好几天的KM浸提终于弄懂了,前两天就一直看来着,然后看不明白,就放着了,今天不信,重拾KM终于磕会了。然后,其实好傻逼,就是匈牙利算法,加了一个+d   -d的过程

    首先来看一个例子(hdu 2255 奔小康赚大钱)

    题意:

    1.村委会有n个人,n个房子

    2.每个人可以为多个房子出不同的价钱

    3.但是每个人只能发配到一个房子(必须每个人一个)

    4.求出村委会能赚到最多的钱

    (手动模拟一边,假如n=3)

    此时 x[n]=y[n]=0;

    有个可以进行匹配的条件,就是 左边的值 + 右边的值 = 其连线的值

    很显然,最开始  4+0=4  即 A 和 3进行匹配,所以

     此时再次将 x[n]=y[n]=0;

    然后为B 寻找匹配项,发现恰好 和3相加 能满足条件,但是呢,3此时已经和A匹配了 ,因为访问过B,3 ,所以 x[B]=1,y[3]=1;

    现在看A能不能找到其他能满足的项,很显然没有,但是x[a]=1(因为被访问了)

    此时就要寻找一个d (d 为 所有被访问过的人,即A,B 与未匹配过的房屋 即 1,2 中,左值右值之和与连线的差的最小值 )

    于是找到此时的d为1,所以给u、所有匹配的人降低d ,所有匹配过的房增加d ,即

    此时,因为A可以找到一个匹配的房了,然后B 恰好也能找到与之相匹配的

     

     此时为C 寻找匹配项,发现并没有满足的,于是自减1

    首先x[n]=y[n]=0;(初始化为从未遍历过)

    再次为C 寻找匹配项(x[C]=1),发现可以与3 (y[3]=1)进行匹配,但是3有了B ,让B寻找其他项(x[b]=1),B可以与1匹配(y[1]=1),但是1有了A,让A 寻找其他匹配(x[A]=1)

    然而,并没有,,所以进行+d,-d这个操作,此时求得d=1;于是得到

    于是重复这个步骤

     

    然后得到:

    然后,皆大欢喜,结束。。。。。。。。。

    代码实现:

     1 #include<cstdio>
     2 #define Max 456
     3 #include<cstring>
     4 using namespace std;
     5 int g[Max][Max];
     6 int lx[Max],ly[Max];
     7 int visx[Max],visy[Max];
     8 int match[Max];
     9 int n;
    10 int findpath(int u);
    11 int KM();
    12 int main()
    13 {
    14     //int T;
    15     //scanf("%d",&T);
    16     while(~scanf("%d",&n))
    17     {
    18         for(int i=1;i<=n;i++)
    19         for(int j=1;j<=n;j++)
    20         scanf("%d",&g[i][j]);
    21         printf("%d
    ",KM());
    22     }
    23     return 0;
    24 }
    25 int findpath(int u)
    26 {
    27     visx[u]=1;
    28     for(int v=1;v<=n;v++)
    29     {
    30         if(!visy[v]&&lx[u]+ly[v]==g[u][v])
    31         {
    32             int t=match[v];visy[v]=1;
    33             if(!t||findpath(t))
    34             {
    35                 match[v]=u;return 1;
    36             }
    37         }
    38     }
    39     return 0;
    40 }
    41 int KM()
    42 {
    43     for(int i=1;i<=n;i++)
    44     {
    45         lx[i]=0x80000000;
    46         ly[i]=0;
    47         for(int j=1;j<=n;j++)
    48         if(lx[i]<g[i][j])
    49         lx[i]=g[i][j];
    50     }
    51     memset(match,0,sizeof(match));
    52     for(int u=1;u<=n;u++)
    53     {
    54         while(1)
    55         {
    56             memset(visx,0,sizeof(visx));
    57             memset(visy,0,sizeof(visy));
    58             if(findpath(u))
    59             break;
    60             int d=0x7fffffff;
    61             for(int i=1;i<=n;i++)
    62             {
    63                 if(visx[i])
    64                 {
    65                     for(int j=1;j<=n;j++)
    66                     if(!visy[j]&&d>lx[i]+ly[j]-g[i][j])
    67                     d=lx[i]+ly[j]-g[i][j];
    68                 }
    69             }
    70             for(int k=1;k<=n;k++)
    71             {
    72                 if(visx[k])
    73                 lx[k]-=d;
    74                 if(visy[k])
    75                 ly[k]+=d;
    76             }
    77         }
    78     }
    79     int sum=0;
    80     for(int i=1;i<=n;i++)
    81     {
    82         int t=match[i];
    83         if(t)
    84         sum+=g[t][i];
    85     }
    86     return sum;
    87 }
  • 相关阅读:
    【转载】多个集合合并成没有交集的集合-实现
    [遇见时光]美团测试实习生面试
    [遇见时光]中科院分词工具NLPIR,Not valid license or your license expired!
    html a标签的target属性
    使用EditPlus技巧,提高工作效率(自动文成文件、语法文件下载)
    android textView 替文字添加下划线 删除线
    Android把自己应用加入到系统文件分享中
    addFooterView 方法注意调用顺序
    android打开当前应用市场简单方法 (ActivityNotFoundException 异常解决)
    The currently displayed page contains invalid values异常
  • 原文地址:https://www.cnblogs.com/ouyang_wsgwz/p/7221726.html
Copyright © 2020-2023  润新知