【模板】二分图最大权完美匹配KM算法

hdu2255模板题

KM是什么意思,详见百度百科

总之知道它可以求二分图最大权完美匹配就可以了,时间复杂度为O(n^3)

给张图。

二分图有了边权,求最大匹配下的最大权值。

所以该怎么做呢?对啊,怎么做呢?

我也不懂啊,看的别人博客

然而并没有将思路,只是模拟了一遍。

核心是在当两个女生都匹配到一个男生时,这两个女生只能降低一下期望值了,降低多少呢?两个妹子都在能选择的其他人中,也就是没参与这轮匹配的男生中,选择一个期望值降低的尽可能小的人。也就是再其他人中选择一个最合适的。

匹配过程用匈牙利算法。

——代码(服用时把注释去掉就好)

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 const int INF = 0x3f3f3f3f;
  8 const int maxn = 301;
  9 int n;
 10 int love[maxn][maxn];
 11 //男女好感度 
 12 int ex_boy[maxn], ex_girl[maxn];
 13 //每个男生期望值,每个妹子期望值 
 14 int match[maxn];
 15 //记录每个男生匹配到的妹子 如果没有则为-1
 16 int slack[maxn];
 17 //记录每个男生如果能被妹子倾心最少还需要多少期望值
 18 bool vis_boy[maxn], vis_girl[maxn];
 19 //记录每一轮匹配匹配到的男生和女生 
 20 
 21 bool find(int i)
 22 {
 23     int j, gap;
 24     vis_girl[i] = 1;
 25     for(j = 1; j <= n; j++)
 26     {
 27         if(vis_boy[j]) continue; //每一轮匹配,每个男生只尝试一次
 28         gap = ex_girl[i] + ex_boy[j] - love[i][j];
 29         if(gap == 0) //如果符合要求
 30         {
 31             vis_boy[j] = 1;
 32             //如果没有找到匹配男生,或者该男生的妹子可以找到其他人 
 33             if(match[j] == -1 || find(match[j]))
 34             {
 35                 match[j] = i;
 36                 return 1;
 37             }
 38         }
 39         else slack[j] = min(slack[j], gap);
 40         // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
 41     }
 42     return 0;
 43 }
 44 
 45 int KM()
 46 {
 47     int i, j, d, ret = 0;
 48     memset(match, -1, sizeof(match));
 49     //初始每个男生都没有匹配到女生 
 50     memset(ex_boy, 0, sizeof(ex_boy));
 51     //初始每个男生期望值为0
 52     
 53     //每个女生的期望值是与她相连的男生的最大好感度
 54     for(i = 1; i <= n; i++)
 55      for(j = 1; j <= n; j++)
 56       ex_girl[i] = max(ex_girl[i], love[i][j]);
 57       
 58     //尝试为每个女生解决归宿问题
 59     for(i = 1; i <= n; i++)
 60     {
 61         memset(slack, 127 / 3, sizeof(slack));
 62         //因为要取小值,初始化无穷大
 63         while(1)
 64         {
 65             //为每个女生解决归宿的方法是:
 66             //如果找不到就降低期望值,直到找到为止
 67             
 68             //记录每轮匹配中男女是否被匹配过
 69             memset(vis_girl, 0, sizeof(vis_girl));
 70             memset(vis_boy, 0, sizeof(vis_boy));
 71             
 72             //找到归宿,退出
 73             if(find(i)) break;
 74             
 75             //如果找不到,就降低期望值
 76             //最小可降低的期望值
 77             d = INF;
 78             for(j = 1; j <= n; j++)
 79              if(!vis_boy[j])
 80               d = min(d, slack[j]);
 81             
 82             for(j = 1; j <= n; j++)
 83             {
 84                 //所有访问过的妹子降低期望值
 85                 if(vis_girl[j]) ex_girl[j] -= d;
 86                 //所有访问过的男生增加期望值
 87                 if(vis_boy[j]) ex_boy[j] += d;
 88             }             
 89         } 
 90     }
 91     
 92     //匹配完成,找出所有匹配的好感度之和
 93     for(i = 1; i <= n; i++) ret += love[match[i]][i];
 94     return ret;
 95 }
 96 
 97 int main()
 98 {
 99     int i, j;
100     while(~scanf("%d", &n))
101     {
102         for(i = 1; i <= n; i++)
103           for(j = 1; j <= n; j++)
104             scanf("%d", &love[i][j]);
105           printf("%d\n", KM());
106     }
107     return 0;
108 }
View Code

 拉闸,变量名改不过来了。

posted @ 2017-04-13 10:57  zht467  阅读(431)  评论(0编辑  收藏  举报