1. 程式人生 > >UVA1349(帶權二分圖最大匹配 --> KM算法模板)

UVA1349(帶權二分圖最大匹配 --> KM算法模板)

amp slack == 還需要 構造 有一個 using lac str

UVA1349

題意:給定一些有向帶權邊,求出把這些邊構造成一個個環,總權值最小

解法:

對於帶權的二分圖的匹配問題可以用通過KM算法求解。

要求最大權匹配就是初始化g[i][j]為0,直接跑就可以;

要求最小權匹配就是初始化g[i][j]為-INF,加邊的時候邊權為負,最後輸出答案的相反數。

因為要求每個點恰好屬於一個圈,意味著每個點都有一個唯一的後繼。 反過來,只要每個點都有唯一的後繼,每個點一定屬於某個圈。

唯一的是我們想到了二分圖的概念,我們對於每個點,建立由u到v的二分圖, 之後問題就轉換成了二分圖上的最小權完美匹配問題

  1 #include<bits/stdc++.h>
  2
#define REP(i, a, b) for(int i = (a); i < (b); i++) 3 #define MEM(a,x) memset(a,x,sizeof(a)) 4 #define INF 0x3f3f3f3f 5 #define MAXN 100+10 6 using namespace std; 7 8 struct KM { 9 int n; 10 int g[MAXN][MAXN]; 11 int Lx[MAXN], Ly[MAXN]; 12 int slack[MAXN];//記錄距X匹配到Y點還需要多少權值
13 int match[MAXN];//記錄每個X點匹配到的Y集中的點 14 bool S[MAXN], T[MAXN]; 15 16 void init(int n) { 17 this->n = n; 18 for (int i = 0; i < n; i++) 19 for (int j = 0; j < n; j++) 20 g[i][j] = -INF; 21 //註意這裏如果是求最大權值匹配和就賦值為0 22 //
最小權值匹配和就是—INF 23 } 24 25 void add_Edge(int u, int v, int val) { 26 g[u][v] = max(g[u][v], val); 27 } 28 29 bool dfs(int i) { 30 S[i] = true; 31 for (int j = 0; j < n; j++) { 32 if (T[j]) continue; 33 int tmp = Lx[i] + Ly[j] - g[i][j]; 34 if (!tmp) { 35 T[j] = true; 36 if (match[j] == -1 || dfs(match[j])) { 37 match[j] = i; 38 return true; 39 } 40 } 41 else slack[j] = min(slack[j], tmp); 42 } 43 return false; 44 } 45 46 void update() { 47 int a = INF; 48 for (int i = 0; i < n; i++) 49 if (!T[i]) a = min(a, slack[i]); 50 for (int i = 0; i < n; i++) { 51 if (S[i]) Lx[i] -= a; 52 if (T[i]) Ly[i] += a; 53 } 54 } 55 56 void km() { 57 for (int i = 0; i < n; i++) { 58 match[i] = -1; 59 Lx[i] = -INF; Ly[i] = 0; 60 for (int j = 0; j < n; j++) 61 Lx[i] = max(Lx[i], g[i][j]); 62 } 63 for (int i = 0; i < n; i++) { 64 for (int j = 0; j < n; j++) slack[j] = INF; 65 while (1) { 66 for (int j = 0; j < n; j++) S[j] = T[j] = false; 67 if (dfs(i)) break; 68 else update(); 69 } 70 } 71 } 72 }Men; 73 74 int main() { 75 int n; 76 while (scanf("%d", &n) == 1 && n) { 77 Men.init(n); 78 REP(u, 0, n) { 79 int v; 80 while (scanf("%d", &v) && v) { 81 int w; scanf("%d", &w); 82 v--; 83 Men.add_Edge(u, v, -w); 84 } 85 } 86 87 Men.km(); 88 int ans = 0, flag = 1; 89 REP(i, 0, n) { 90 if (Men.g[Men.match[i]][i] == -INF) { 91 //有未匹配到,就是不成功,因為題目要求的是完美匹配 92 flag = 0; 93 break; 94 } 95 ans += Men.g[Men.match[i]][i];//累加權值 96 } 97 if (!flag) printf("N\n"); 98 else printf("%d\n", -ans);//最後是輸出的是負數 99 } 100 return 0; 101 }

UVA1349(帶權二分圖最大匹配 --> KM算法模板)