码迷,mamicode.com
首页 > 编程语言 > 详细

【km算法模板+总结】

时间:2017-08-13 22:17:53      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:int   地方   修改   疑惑   efi   核心   lin   for   mat   

今天下午看了一下午的km算法,因为大佬的博客介绍非常简短,所以自己一直没有弄清楚一些细节问题,好在回来翻到了一个比较好的csdn专栏,介绍比较详细,自己才算弄懂了很多疑惑的地方,二分图最佳完美匹配

总结一下算法:

思想:km算法就是改变一些可行点的标号,不断增加图中可行边的总数,直到图中存在仅由可行边组成的完美匹配为止。核心部分就是控制修改可行顶标的值直到最终可到达一个完美匹配。

流程:1)初始化可行顶标lx和ly的值(ly=0显然是可行的,保证任意x一个x方点至少一条可行边)

   2)从每个x方点开始dfs增广,用匈牙利算法寻找相等子图的完备匹配。

   3)如果没有找到增广路,改变可行顶标的值。

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

注意两点:一是只找可行边,二是要把搜索过程中遍历到的X方点全部记下来,以便进行后面的修改

 1 #define INF 0x3f3f3f3f
 2 int dfs(int x)
 3 {
 4     int y,tmp;
 5     visx[x] = 1;
 6     for(y = 1; y <= ny; y ++)
 7     {
 8         if(!visy[y])
 9         {
10             tmp = lx[x] + ly[y] - w[x][y];
11             if(tmp == 0)
12             {
13                 visy[y] = 1;
14                 if(linker[y]==-1||dfs(linker[y]))
15                 {
16                     linker[y] = x;
17                     return 1;
18                 }
19             }
20             else if(slack[y] > tmp)
21                 slack[y] = tmp;//x,y不在相等子图中且y不在增广轨中 
22         }
23     }
24     return 0;
25 }
26 int km()
27 {
28     int x,y,sum,i,d,j;
29     memset(linker,-1,sizeof(linker));
30     memset(ly,0,sizeof(ly));
31     for(i = 1; i <= nx; i ++)
32         for(j = 1, lx[i] = -INF; j <= ny; j ++)
33             if( lx[i] < w[i][j])
34                 lx[i] = w[i][j];
35     for(x = 1; x <= nx; x ++)
36     {
37         for(i = 1; i <= ny; i ++)
38             slack[i] = INF;//每次换新的结点都要初始化slack 
39         while(1)
40         {//因为每次dfs都需要更新 
41             memset(visx,0,sizeof(visx));
42             memset(visy,0,sizeof(visy));
43             if(dfs(x))
44                 break;
45             //dfs失败,所以x一定在增广轨中,y一定不在增广轨中 
46             d = INF;
47             for(i = 1; i <= ny; i ++)
48                 if(!visy[i]&&d > slack[i])
49                     d = slack[i];
50             for(i = 1; i <= nx; i ++)
51                 if(visx[i])
52                     lx[i] -=d;
53             for(i = 1; i <= ny; i ++)
54                 if(visy[i])
55                     ly[i] +=d;
56                 else
57                     slack[i] -=d;//修改顶标之后,将所有的slack减去d
58         //因为lx减去了d,而slack[y]=lx[x]-ly[y]-w[x][y].而y是不在增广轨中的,第二类边 
59         }    
60     }
61     sum = 0;
62     for(i = 1; i <= ny; i ++)
63         if(linker[i]!=-1)
64             sum += w[linker[i]][i];
65     return sum;
66 }

 

【km算法模板+总结】

标签:int   地方   修改   疑惑   efi   核心   lin   for   mat   

原文地址:http://www.cnblogs.com/chengdongni/p/7354979.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!