二分图最大权完美匹配KM算法

KM算法二分图

KM求得二分图与普通二分图的不同之处在于:此二分图的每条边(男生女生)上都附了权值(好感度)。然后,求怎样完美匹配使得权值之和最大。

这,不止一般的麻烦啊。

可以通过一个期望值来求。

大致思路就是:

每个男生女生都有期望值,男生一开始全部为0,女生一开始则是可能的最大值。

匹配的条件为男生的期望值加上女生的期望值等于他们之间的权值(好感度)。

每次如果不能匹配,就降一下参加匹配的女生的期望值,加一下参加匹配的男生的期望值。

基本思路就这样,具体参考别人的一篇博客

代码也是人家的。。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int MAXN=305;
 6 const int INF=0x3f3f3f3f;
 7 int love[MAXN][MAXN];//记录每个妹子和每个男生的好感度
 8 int ex_girl[MAXN];//每个妹子的期望值
 9 int ex_boy[MAXN];//每个男生的期望值
10 bool vis_girl[MAXN];//记录每一轮匹配匹配过的女生
11 bool vis_boy[MAXN];//记录每一轮匹配匹配过的男生
12 int match[MAXN];//记录每个男生匹配到的妹子 如果没有则为-1
13 int slack[MAXN];//记录每个汉子如果能被妹子倾心最少还需要多少期望值
14 int N;
15 bool dfs(int girl){
16     vis_girl[girl]=true;
17     for(int boy=0;boy<N;++boy) {
18         if(vis_boy[boy])
19             continue;//每一轮匹配 每个男生只尝试一次
20         int gap=ex_girl[girl]+ex_boy[boy]-love[girl][boy];
21         if(gap==0){//如果符合要求
22             vis_boy[boy]=true;
23             if(match[boy]==-1||dfs(match[boy])){//找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
24                 match[boy]=girl;
25                 return true;
26             }
27         }
28         else
29             slack[boy]=min(slack[boy],gap);//slack可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值
30     }
31     return false;
32 }
33 int KM(){
34     memset(match,-1,sizeof match);//初始每个男生都没有匹配的女生
35     memset(ex_boy,0,sizeof ex_boy);//初始每个男生的期望值为0
36     //每个女生的初始期望值是与她相连的男生最大的好感度
37     for(int i=0;i<N;++i){
38         ex_girl[i]=love[i][0];
39         for(int j=1;j<N;++j)
40             ex_girl[i]=max(ex_girl[i],love[i][j]);
41     }
42     //尝试为每一个女生解决归宿问题
43     for(int ii=0;ii<N;++ii){
44         fill(slack,slack+N,INF);//因为要取最小值 初始化为无穷大
45         while(1){
46             //为每个女生解决归宿问题的方法是:如果找不到就降低期望值,直到找到为止
47             //记录每轮匹配中男生女生是否被尝试匹配过
48             memset(vis_girl,false,sizeof vis_girl);
49             memset(vis_boy,false,sizeof vis_boy);
50             if(dfs(ii))
51                 break;//找到归宿 退出
52             //如果不能找到 就降低期望值
53             int d=INF;//最小可降低的期望值
54             for(int j1=0;j1<N;++j1)
55                 if(!vis_boy[j1])
56                     d=min(d,slack[j1]);
57             for(int j2=0;j2<N;++j2){
58                 //所有访问过的女生降低期望值
59                 if(vis_girl[j2])
60                     ex_girl[j2]-=d;
61                 //所有访问过的男生增加期望值
62                 if(vis_boy[j2])
63                     ex_boy[j2]+=d;
64                 //没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
65                 else
66                     slack[j2]-=d;
67             }
68         }
69     }
70     //匹配完成 求出所有配对的好感度的和
71     int res=0;
72     for(int iii=0;iii<N;++iii)
73         res+=love[match[iii]][iii];
74     return res;
75 }
76 int main(){
77     scanf("%d",&N);
78     for(int i=0;i<N;++i)
79         for(int j=0;j<N;++j)
80             scanf("%d",&love[i][j]);
81     printf("%d\n",KM());
82     return 0;
83 }
View Code

具体实现过程还是得自己理解,实在不行就自己调试几遍,提供一个数据:

3
3 0 4
2 1 3
0 0 5

直接就是那篇博客的图。

 

posted @ 2017-04-21 09:30  江屿  阅读(1639)  评论(0编辑  收藏  举报