1. 程式人生 > >【km算法模板+總結】

【km算法模板+總結】

sum () 核心部分 view 博客 流程 || linker ack

今天下午看了一下午的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算法模板+總結】