题目描述
我的公寓里有 nnn 台计算机,我朋友的公寓里也有 nnn 台计算机。在每个公寓内,一些计算机对之间通过 AcidNet\texttt{AcidNet}AcidNet 电缆连接(忽略路由器)。每条连接都有特定的带宽(字节/秒)。我的朋友总是吹嘘他的计算机网络速度,并向我展示他的 n×nn \times nn×n 带宽表格,其中列出了每对计算机之间的带宽。
我的网络较慢,我想重建它。我需要知道如何连接我的计算机,才能得到相同的 n×nn \times nn×n 带宽表格。由于我不想购买太多 AcidNet\texttt{AcidNet}AcidNet 电缆,需要找到连接数最少的解决方案。我可以使用任何整数带宽的 AcidNet\texttt{AcidNet}AcidNet 电缆,它们在商店中价格相同。
问题本质:给定一个 n×nn \times nn×n 的对称表格 TTT,其中 T[u][v]T[u][v]T[u][v] 表示计算机 uuu 和 vvv 之间的最大流(带宽),找到一个边数最少的无向图,使得该图中任意两点 u,vu, vu,v 之间的最大流等于 T[u][v]T[u][v]T[u][v]。
输入格式
- 第一行:测试用例数 NNN
- 每个测试用例:
- 一行包含 nnn (0<n≤2000 < n \leq 2000<n≤200)
- nnn 行,每行 nnn 个整数,表示表格 TTT
- T[u][u]=0T[u][u] = 0T[u][u]=0
- T[u][v]=T[v][u]>0T[u][v] = T[v][u] > 0T[u][v]=T[v][u]>0
- T[i][j]≤10000T[i][j] \leq 10000T[i][j]≤10000
输出格式
对于每个测试用例:
- 如果无解:输出
Impossible - 如果有解:输出边数 mmm,然后 mmm 行,每行三个整数 u v wu\ v\ wu v w 表示连接 uuu 和 vvv 的电缆带宽为 www
题目分析
问题本质理解
这是一个图论逆问题:给定所有点对之间的最大流值(即最小割容量),要求重构出边数最少的原图。
关键观察:
- 在无向图中,两点间的最大流等于它们之间的最小割容量
- 在树结构中,两点 u,vu, vu,v 之间的最大流等于连接路径上的最小边权
- 为了最小化边数,我们希望找到一棵树(n−1n-1n−1 条边)
理论基础
重要定理:如果对称表格 TTT 满足以下条件,则存在一棵树使得任意两点 u,vu, vu,v 在树路径上的最小边权等于 T[u][v]T[u][v]T[u][v]:
- T[u][u]=0T[u][u] = 0T[u][u]=0(对角线为 0)
- T[u][v]=T[v][u]T[u][v] = T[v][u]T[u][v]=T[v][u](对称性)
- 对于所有 i,j,ki, j, ki,j,k(k≠i,k≠jk \neq i, k \neq jk=i,k=j),满足三角不等式:
T[i][j]≥min(T[i][k],T[k][j])T[i][j] \geq \min(T[i][k], T[k][j])T[i][j]≥min(T[i][k],T[k][j])
算法思路
- 可行性检查:验证表格 TTT 是否满足三角不等式
- 构建最大生成树:如果满足条件,使用 Kruskal\texttt{Kruskal}Kruskal 算法构建最大生成树
- 输出结果:直接输出最大生成树的所有边
为什么使用最大生成树?
- 在最小生成树中,路径上的最小边权是瓶颈
- 为了满足 T[u][v]T[u][v]T[u][v] 的要求,需要路径上的最小边权尽可能大
- 最大生成树能保证对于任意两点 u,vu, vu,v,它们之间路径的最小边权等于 T[u][v]T[u][v]T[u][v]
解题步骤详解
步骤 1:输入与验证
读取输入数据并验证基本性质:
- 对角线必须为 0
- 矩阵必须对称
- 所有值非负
步骤 2:三角不等式检查
对于所有 i<ji < ji<j 和 k≠i,k≠jk \neq i, k \neq jk=i,k=j,检查:
T[i][j]≥min(T[i][k],T[k][j])T[i][j] \geq \min(T[i][k], T[k][j])T[i][j]≥min(T[i][k],T[k][j])
如果任何一对违反此条件,则输出 Impossible。
步骤 3:构建最大生成树
- 将所有可能的边 (i,j,T[i][j])(i, j, T[i][j])(i,j,T[i][j]) 加入边集
- 按边权降序排序(最大生成树)
- 使用 Kruskal\texttt{Kruskal}Kruskal 算法构建生成树
- 使用并查集管理连通分量
步骤 4:输出结果
输出树的 n−1n-1n−1 条边,确保每条边只输出一次(u<vu < vu<v)。
复杂度分析
- 时间复杂度:O(n3)O(n^3)O(n3)
- 三角不等式检查:O(n3)O(n^3)O(n3)
- 排序边:O(n2logn)O(n^2 \log n)O(n2logn)
- Kruskal\texttt{Kruskal}Kruskal 算法:O(n2α(n))O(n^2 \alpha(n))O(n2α(n))
- 空间复杂度:O(n2)O(n^2)O(n2)
代码实现
// It's all about the Bandwidth
// UVa ID: 11603
// Verdict: Accepted
// Submission Date: 2025-11-17
// UVa Run Time: 0.010s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int u, v, w;
bool operator<(const Edge& other) const {
return w > other.w; // 最大生成树
}
};
vector<int> parent;
int findSet(int x) {
if (parent[x] != x)
parent[x] = findSet(parent[x]);
return parent[x];
}
bool unionSet(int x, int y) {
int rx = findSet(x), ry = findSet(y);
if (rx == ry) return false;
parent[rx] = ry;
return true;
}
void solve() {
int n;
cin >> n;
vector<vector<int>> t(n, vector<int>(n));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> t[i][j];
// 检查三角不等式,忽略 k=i 或 k=j 的情况
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = 0; k < n; k++) {
if (k != i && k != j && t[i][j] < min(t[i][k], t[k][j])) {
cout << "Impossible\n";
return;
}
}
}
}
// 构建边列表
vector<Edge> edges;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
edges.push_back({i, j, t[i][j]});
sort(edges.begin(), edges.end());
// 最大生成树
parent.resize(n);
for (int i = 0; i < n; i++) parent[i] = i;
vector<vector<pair<int, int>>> tree(n);
int mstEdges = 0;
for (const auto& e : edges) {
if (unionSet(e.u, e.v)) {
tree[e.u].push_back({e.v, e.w});
tree[e.v].push_back({e.u, e.w});
mstEdges++;
if (mstEdges == n - 1) break;
}
}
// 输出结果
cout << n - 1 << "\n";
for (int u = 0; u < n; u++)
for (const auto& nb : tree[u])
if (u < nb.first)
cout << u << " " << nb.first << " " << nb.second << "\n";
}
int main() {
int N;
cin >> N;
for (int caseNum = 1; caseNum <= N; caseNum++) {
cout << "Case #" << caseNum << ": ";
solve();
}
return 0;
}
总结
本题的关键在于理解最大流表格与树结构之间的关系。通过三角不等式的验证和最大生成树的构建,我们能够高效地解决这个图论逆问题。算法的时间复杂度为 O(n3)O(n^3)O(n3),在 n≤200n \leq 200n≤200 的约束下完全可行。
这种将复杂问题转化为经典图论算法(如最大生成树)的思路,在竞赛中非常实用,值得学习和掌握。

1785

被折叠的 条评论
为什么被折叠?



