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 ", KM()); 106 } 107 return 0; 108 }
拉闸,变量名改不过来了。