最大权匹配KM算法模板

 Kuhn-Munkras算法流程:

  (1)初始化可行顶标的值

  (2)用匈牙利算法寻找完备匹配

  (3)若未找到完备匹配则修改可行顶标的值

  (4)重复(2)(3)直到找到相等子图的完备匹配为止

直接附代码

 1 bool dfs(int x)//匈牙利算法寻找x的增广路径 以x为根的M的交错树 
 2 {
 3     int y,t;
 4     visx[x]=true;
 5     for(y=0;y<N;y++)
 6     {
 7         if(visy[y])    continue;//找增广路径的过程中不妨问已经访问过的顶点 
 8         t=lx[x]+ly[y]-g[x][y];//在相等子图中寻找匹配的增广路径
 9         if(t==0)
10         {
11             visy[y]=true;
12             if(linky[y]==-1||dfs(linky[y]))
13             {
14                 linky[y]=x;
15                 return true;
16             }
17         }
18         else//因为本来就需要将一条x顶点在交错树中,y顶点不在交错树中的边扩展进交错树来
19         //所以只改变这些不在等子图中的边的y顶点的松弛量 
20         {
21             if(slack[y]>t)
22                 slack[y]=t;
23         }
24     }
25     return false;
26 }
27 //外层的匈牙利算法需要O(2)的时间,而修改顶标时由于要枚举所有的边所以也需要O(2)的时间
28 //所以总时间是O(4) 
29 //引入松弛量以后改变顶标就不需要枚举每一条边,只需要枚举不在交错树中的y的松弛量,所以
30 //时间复杂度降为O(3) 
31 int KM()
32 {
33     int i,j,x,d,res=0;
34     memset(linky,-1,sizeof(linky));
35     memset(lx,0,sizeof(lx));//x的顶标
36     memset(ly,0,sizeof(ly));//y的顶标
37     for(i=0;i<N;i++)
38         for(j=0;j<N;j++)
39             if(g[i][j]>lx[i])
40                 lx[i]=g[i][j];//一开始x的顶标为所有与x相连的边中权值最大的边的权值,y的顶标为0 
41     for(x=0;x<N;x++)
42         {//在匈牙利算法中从每个x出发寻找增广路,如果找到就在匹配值上加1,这是为了寻找最大匹配
43         //而在此处,必须找到完备匹配,所以对于每一个x中的顶点,找到其增广路就跳出,找不到的话
44         //就需要修改顶标值直至找到为止 
45             for(i=0;i<N;i++)
46                 slack[i]=INF;
47             while(true)
48             {//无限循环直至找到完备匹配 
49                 memset(visx,false,sizeof(visx));
50                 memset(visy,false,sizeof(visy));
51                 if(dfs(x))break;
52                 d=INF;
53                 for(i=0;i<N;i++)
54                 {
55                     if(!visy[i]&&d>slack[i]))//注意是取所有不在交错树中的y顶点的松弛量的最小值作为d的值 
56                             d=slack[i];
57                 }
58                 for(i=0;i<N;i++)
59                     if(visx[i])  lx[i]-=d;
60                 for(i=0;i<N;i++)
61                     if(visy[i])  ly[i]+=d;
62                     else slack[i]-=d;
63             }
64         }
65     for(i=0;i<N;i++)
66         if(linky[i]!=-1)    res+=g[linky[i]][i];
67     return res;
68 }

 plus:若要求最小权匹配,只需将所有边权值取反,同时让x的顶标能取到负值中的最大值。

原文地址:https://www.cnblogs.com/-dante-/p/3269019.html