题目链接 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 ∈ V G.
- Let T = ( V T, E T) be a tree with V T = V G, denote the set of edges in an s- t path by P st for each s, t ∈ V T.
Then T is said to be a Gomory–Hu tree of G if
- λ st = min e∈Pst c( S e, T e) for all s, t ∈ V G,
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 ,
而把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;
}