題意:給定二分圖,有邊權,求最大邊權匹配。邊權非負。算法
解:KM算法求解最大權完備匹配。數組
完備匹配就是點數少的那一邊每一個點都有匹配。ide
爲了讓完備匹配與最大權匹配等價,咱們添加若干條0邊使之成爲徹底二分圖(自造名詞別在乎......)函數
爲了讓左邊成爲點數較少的一邊,咱們還要添加一些虛點,m = max(n,m)spa
而後求解完備匹配。code
KM的DFS寫法會被卡成n4,若是你不在乎能夠寫......反正在uoj上會被卡爆。blog
模板就不放了,反正沒啥用,放了還我 誤 我 自 己。get
過程就是一次爲每一個點尋找匹配。首先每一個點都有個頂標(指望匹配值),最後要使得每一條匹配邊(x, y)知足w[x] + w[y] = val(x, y)string
而後每一個右邊的點還有個need數組,通常是叫作slack,就是鬆弛量,也就是當前這個點最少要把w減去多少才能匹配上。it
還有個D是min slack,也就是全局最少減小D才能獲得匹配。
匹配的時候跟匈牙利同樣DFS,注意到一個點以後若是w[x] + w[y] = val(x, y)則這條邊可用,打上vis,不然用差值更新need y
若是沒有匹配就update一遍,每一個有vis的左邊減去D,右邊加上D。而後繼續直到有匹配爲止。
BFS寫法
這個我不太懂...話說DFS原本就不懂了,還糾結這個幹啥。
右邊節點有個pre數組表示它是誰更新來的,也就是若是它進入增廣路,那麼它前面的右邊節點是pre
在BFS函數裏首先設置BFS起點是右邊0匹配左邊x,而後嘗試爲x找到增廣路。
枚舉每一個未被vis的y,獲得w[x] + w[y]與val(x, y)的差值。
用這個差值更新need[y],若是差值比need[y]小,就代表y的前一個節點是mat[x]的話會更佳,令pre[y] = u(u表示正在匹配x的節點,也就是上一個x準備匹配的節點)
用need[y]更新D,若是need[y] < D則代表全局上下一個點選擇y更優,令nex = y(此處nex是下一輪的u)
而後更新一遍,讓全部vis的右邊節點(固然也包括一開始咱們虛擬跟x匹配的右邊0號點)w += D,而與之匹配的左邊節點w -= D
結束條件是找到的這個u沒有匹配。此時增廣路就找到了。
而後把交錯路取反,也就是每一個u的匹配變成上一個u的匹配,直到倒數第二個u匹配x。
啊我到底在口胡些什麼
1 //thanks to yyb 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 6 typedef long long LL; 7 const int N = 410; 8 const LL INF = 0x3f3f3f3f3f3f3f3f; 9 10 int vis[N * 2], mat[N * 2], Time, pre[N * 2], n, m; 11 LL val[N][N], w[N * 2], need[N * 2]; 12 13 void BFS(int x) { 14 memset(need, 0x3f, sizeof(need)); 15 memset(pre, 0, sizeof(pre)); 16 int u = 0, nex; 17 mat[u] = x; 18 do { 19 x = mat[u]; 20 LL D = INF; 21 vis[u] = Time; 22 for(int y = n + 1; y <= n + m; y++) { 23 if(vis[y] == Time) { 24 continue; 25 } 26 LL t = w[x] + w[y] - val[x][y - n]; 27 if(t < need[y]) { // update need pre 28 need[y] = t; 29 pre[y] = u; 30 } 31 if(need[y] < D) { // update D nex 32 D = need[y]; 33 nex = y; 34 } 35 } 36 // update 37 w[mat[0]] -= D; // do not forget! 38 w[0] += D; 39 for(int i = n + 1; i <= n + m; i++) { 40 if(vis[i] == Time) { 41 w[mat[i]] -= D; 42 w[i] += D; 43 } 44 else { 45 need[i] -= D; 46 } 47 } 48 u = nex; 49 } while(mat[u]); 50 51 while(u) { // update path 52 mat[u] = mat[pre[u]]; 53 u = pre[u]; 54 } 55 56 return; 57 } 58 59 int main() { 60 int q; 61 scanf("%d%d%d", &n, &m, &q); 62 m = std::max(n, m); 63 for(int i = 1; i <= q; i++) { 64 int x, y; 65 LL z; 66 scanf("%d%d%lld", &x, &y, &z); 67 val[x][y] = std::max(val[x][y], z); 68 w[x] = std::max(w[x], val[x][y]); 69 } 70 for(int i = 1; i <= n; i++) { 71 ++Time; // ++Time 72 BFS(i); 73 } 74 LL ans = 0; 75 for(int i = n + 1; i <= n + m; i++) { 76 if(val[mat[i]][i - n]) { // do not forget " - n"! 77 mat[mat[i]] = i; 78 ans += val[mat[i]][i - n]; 79 } 80 } 81 printf("%lld\n", ans); 82 for(int i = 1; i <= n; i++) { 83 printf("%d ", mat[i] ? mat[i] - n : mat[i]); 84 } 85 return 0; 86 }
最後感謝YYB神犇,我是照抄他的代碼的%%%%%%。