大意:告诉你一些国家和一些单项路,每条路连接两个国家,告诉你之间的距离,现在要使每个国家都在一个环中
求最小距离
分析:这是做过的第二个多个环的并的问题
每个点的入读和出度都为1
把n个点拆点
由于二分图最优匹配的性质可知每个点都会出现在匹配中
相当于每个点出现一次
左边为出度点 有边为入读点
值得注意的是两个国家可能会有多条路
要选取最短的
----想起东北赛死在这上边了 ----全都是泪啊
代码:
1 #include2 #include 3 #include 4 #include 5 #include 6 using namespace std; 7 8 const int maxn = 205; 9 const int INF = 1000000000; 10 11 struct KM { 12 int n; 13 vector G[maxn]; 14 int W[maxn][maxn]; 15 int Lx[maxn], Ly[maxn]; 16 int Left[maxn]; 17 bool S[maxn], T[maxn]; 18 19 void init(int n) { 20 this -> n = n; 21 for(int i = 0; i <= n; i++) G[i].clear(); 22 memset(W, 0, sizeof(W)); 23 } 24 25 void AddEdge(int u, int v, int w) { 26 if(W[u][v] == 0) { 27 G[u].push_back(v); 28 W[u][v] = -w; 29 } else if(w < - W[u][v]) { 30 W[u][v] = -w; 31 } 32 } 33 34 bool match(int u) { 35 S[u] = true; 36 for(int i = 0; i < G[u].size(); i++) { 37 int v = G[u][i]; 38 if(Lx[u] + Ly[v] == W[u][v] && !T[v]) { 39 T[v] = true; 40 if(Left[v] == -1 || match(Left[v])) { 41 Left[v] = u; 42 return true; 43 } 44 } 45 } 46 return false; 47 } 48 49 void update() { 50 int a = INF; 51 for(int u = 1; u <= n; u++) if(S[u]) 52 for(int i = 0; i < G[u].size(); i++) { 53 int v = G[u][i]; 54 if(!T[v]) a = min(a, Lx[u] + Ly[v] - W[u][v]); 55 } 56 for(int i = 1; i <= n; i++) { 57 if(S[i]) Lx[i] -= a; 58 if(T[i]) Ly[i] += a; 59 } 60 } 61 62 int solve() { 63 for(int i = 1; i <= n; i++) { 64 Left[i] = -1; 65 Ly[i] = 0; 66 Lx[i] = 0; 67 for(int j = 1; j <= n; j++) { 68 if(W[i][j] != INF) { 69 Lx[i] = max(Lx[i], W[i][j]); 70 } 71 } 72 } 73 for(int u = 1; u <= n; u++) { 74 for(; ;) { 75 for(int i = 1; i <= n; i++) S[i] = T[i] = false; 76 if(match(u)) break; else update(); 77 } 78 } 79 int ans = 0; 80 for(int i = 1; i <= n; i++) { 81 ans += Lx[i] + Ly[i]; 82 } 83 return ans; 84 } 85 }; 86 87 KM g; 88 89 int main() { 90 int t; 91 int n, m; 92 int u, v, w; 93 scanf("%d",&t); 94 while(t--) { 95 scanf("%d %d",&n, &m); 96 g.init(n); 97 while(m--) { 98 scanf("%d %d %d",&u, &v, &w); 99 g.AddEdge(u, v, w );100 }101 printf("%d\n", -g.solve()) ;102 }103 return 0;104 }