題目連結 http://acm.hdu.edu.cn/showproblem.php?pid=4700
Gomory–Hu tree http://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree
Gomory–Hu tree的定義
Let G = ((VG, EG), c) be an undirected graph withc(u,v) being the capacity of the edge (u,v) respectively.
-
Denote the minimum capacity of an
s-
t cut by λst for each
s,
t ∈
VG.
-
Let
T = (
VT,
ET) be a tree with
VT =
VG, denote the set of edges in an
s-
t path by
Pst for each
s,
t ∈
VT.
Then T is said to be a Gomory–Hu tree of G if
-
λst = mine∈Pst
c(
Se,
Te) for all
s,
t ∈
VG,
where
- Se and Te are the two connected components ofT∖{e} in the sense that (Se,
Te) form as-t cut in G, and
- c(Se, Te) is the capacity of the cut inG.
通俗來講就是對任意的 兩個節點s,t,Gomory-Hu tree 儲存的是他們各自相鄰節點的最大流。
要求兩個點的 最大流的話,就是求 從 s點沿著樹的邊走到t,其中的最小的邊的權值。
此題的話,標準題解裡的解釋是: 如果存在這樣要求的一副圖的話,必然存在它所對應的 Gomory–Hu tree ,
而把Gomory–Hu tree的非相鄰邊設定為0,也就是可以成立的一個答案了。
標準題解:
遞迴構造
令 f∗ = mina̸=b Fa,b
令 A = {v0 } ∪ {v : Fv,v0 > f∗ }, B = {v : Fv,v0 = f∗ }。
若 B = ∅,失敗
若 ∃(a ∈ A, b ∈ B)Fa,b > f∗ ,失敗
遞迴構造 A, B
取 a∗ ∈ A, b∗ ∈ B,加邊 (a∗ , b∗ ),容量是 f∗
代碼:
#include <cassert>#include <cstdio>#include <cstring>#include <climits>#include <vector>#include <algorithm>#define SIZE(v) ((int)((v).size()))#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)const int N = 100;int n, cut[N][N], graph[N][N];bool check(std::vector <int> vs) { if (SIZE(vs) <= 1) { return true; } int bridge = INT_MAX; foreach (u, vs) { foreach (v, vs) { bridge = std::min(bridge, cut[*u][*v]); } } int u0 = vs.front(); std::vector <int> v0, v1; foreach (iter, vs) { int v = *iter; if (cut[u0][v] > bridge) { v0.push_back(v); } else { v1.push_back(v); } } if (v0.empty() || v1.empty()) { return false; } graph[v0.front()][v1.front()] = graph[v1.front()][v0.front()] = bridge; foreach (u, v0) { //兩個集合 v0跟v1中的最大流是 bridge,如果給出的條件中 flow(a,b) > bridge,則與條件矛盾,構造不出該圖形 foreach (v, v1) { if (cut[*u][*v] != bridge) { return false; } } } return check(v0) && check(v1);}int main() {//freopen("1005.in","r",stdin);//freopen("10050.out","w",stdout); freopen("temp.in","r",stdin); while (scanf("%d", &n) == 1) { //printf("%d\n",n); assert(1 <= n && n <= N); for (int i = 0; i < n; ++ i) { for (int j = 0; j < n; ++ j) { assert(scanf("%d", &cut[i][j]) == 1); // if(j!=n-1)printf("%d ",cut[i][j]); // else printf("%d",cut[i][j]); if (i == j) { assert(cut[i][j] == -1); cut[i][j] = INT_MAX; } else { assert(0 <= cut[i][j] && cut[i][j] <= 1000000000); } } // puts(""); } for (int i = 0; i < n; ++ i) { for (int j = 0; j < n; ++ j) { assert(cut[i][j] == cut[j][i]); } } std::vector <int> vertices; for (int i = 0; i < n; ++ i) { vertices.push_back(i); } memset(graph, 0, sizeof(graph)); for (int i = 0; i < n; ++ i) { graph[i][i] = -1; } if (check(vertices)) { puts("YES"); for (int i = 0; i < n; ++ i) { for (int j = 0; j < n; ++ j) { //printf("%d%c", i == j ? -1 : 0, j == n - 1 ? '\n' : ' '); printf("%d%c", graph[i][j], j == n - 1 ? '\n' : ' '); } } } else { puts("NO"); } } //puts(check(vertices) ? "YES" : "NO"); return 0;}