1 条题解
-
0
题目很难懂啊,我真的想吐槽了...
题目 P9466
(对我来说)易懂版:(感觉没理解错)
现在有 个点,每对点给出了两个变量 和 。 你需要构造一张“合法”的联通图。 图的每条边 宽度为 ,你需要将宽度划分为两部分,分别记为 和 。
合法: 对于每一对点 之间的所有路径,对于每一条路径用 记录路径间 的最小值,满足 ,用 记录路径间 的最小值,满足 。
分析
首先考虑合法的必要条件之一:对于三个不同的点 必须满足 。 同理。(可以反证法证明)
如果建一张完全图,在数据合法的情况下一定合法,但完全图的边有很多,考虑能不能建树。
我们先只考虑 ,以 为依据建最大生成树。对于任意三个不同的点 ,如果遍历到 时 已联通,那么满足 。再结合之前的必要条件,我们就得到了 ,则此时哪怕不把 加入也是合法的。
单独考虑 建树同理。
然后我们把两张图结合起来。 对于现在的图,我们加入的边有一个对应的 。如果 ,那么我们将无法满足 间最短路的最大值为 所以这种边(即 的边)是一定不能加进去的,在建树的时候之间跳过就行。( 是一样的)。 再考虑 的情况是否合法。此时 则在把两张图结合起来后,不影响最小值最大为 ,是合法的。 同理。
综上,在把不合法的边都舍弃的情况下,分别以 为依据建最大生成树,然后再把它们结合起来就是答案。 如果不连通则无解。
代码
#include<bits/stdc++.h> using namespace std; const int maxn = 600; int n, w; int c[maxn][maxn], b[maxn][maxn], f[maxn]; bool visb[maxn][maxn], visc[maxn][maxn]; int find(int x){ if(f[x] == x) return x; return f[x] = find(f[x]); } void uni(int x, int y){ x = find(x), y = find(y); f[x] = y; } struct E{ int u, v, w; bool operator < (const E &x)const{ return w > x.w; } }; vector<E> eb, ec; bool check(){ for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ for(int k = 0; k < n; k++){ if(i == j || j == k || i == k) continue; if(b[i][j] < min(b[i][k], b[k][j])) return 0; if(c[i][j] < min(c[i][k], c[k][j])) return 0; } } } return 1; } int main(){ cin >> n >> w; for(int i = 1; i < n; i++){ for(int j = 0; j < i; j++){ cin >> c[j][i]; c[i][j] = c[j][i]; } } for(int i = 1; i < n; i++){ for(int j = 0; j < i; j++){ cin >> b[j][i]; b[i][j] = b[j][i]; } } if(!check()) return cout << "NO" << endl, 0; for(int j = 1; j < n; j++){ for(int i = 0; i < j; i++){ if(b[i][j] + c[i][j] >= w){ eb.push_back({i, j, b[i][j]}); ec.push_back({i, j, c[i][j]}); } } } sort(eb.begin(), eb.end()); sort(ec.begin(), ec.end()); for(int i = 0; i < n; i++) f[i] = i; for(auto e : eb){ int u = e.u, v = e.v; if(find(u) == find(v)) continue; uni(u, v); visb[u][v] = 1; } int cnt = 0; for(int i = 0; i < n; i++){ if(f[i] == i) cnt++; f[i] = i; } if(cnt != 1) return cout << "NO" << endl, 0; for(auto e : ec){ int u = e.u, v = e.v; if(find(u) == find(v)) continue; uni(u, v); visc[u][v] = 1; } cnt = 0; for(int i = 0; i < n; i++){ if(f[i] == i) cnt++; } if(cnt != 1) return cout << "NO" << endl, 0; vector<E> ans; for(int i = 0; i < n; i++){ for(int j = i+1; j < n; j++){ if(visb[i][j]){ ans.push_back({i, j, b[i][j]}); } if(visc[i][j]){ ans.push_back({i, j, w - c[i][j]}); } } } cout << ans.size() << endl; for(auto e : ans){ cout << e.u << " " << e.v << " " << e.w << endl; } return 0; }
- 1
信息
- ID
- 10937
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者