每周至少五篇博客:(1/5)
https://atcoder.jp/contests/abc243/tasks/abc243_e
题意
给你一个简单连接的无向图,有 NNN 个顶点和 MMM 条边。
边 iii 连接顶点 AiA_iAi 和顶点 BiB_iBi ,长度为 CiC_iCi 。
让我们在满足以下条件的情况下删除一些边。求可删除的最大边数。
- 删除后的图仍然是连通的。
- 对于每一对顶点 (s,t)(s, t)(s,t) 而言, sss 和 ttt 之间的最短距离在删除前后保持不变。
思路
首先如果我们有上述的三条边 u→k,u→v,k→vu \rightarrow k, u \rightarrow v, k \rightarrow vu→k,u→v,k→v 并且满足 distu,v≥distu,k+distk,vdist_{u, v} \ge dist_{u, k} + dist_{k, v}distu,v≥distu,k+distk,v,那么 u→vu \rightarrow vu→v 这条边是可以删除的
看到数据范围很小,并且这里是每个点到其他点的最短路长度,所以应该想到Floyd算法
考虑Floyd的迭代过程:
- 对于点 u,v,ku, v, ku,v,k ,如果满足 distu,v>distu,k+distk,vdist_{u, v} > dist_{u, k} + dist_{k, v}distu,v>distu,k+distk,v 那么使得 distu,v←distu,k+distk,vdist_{u, v} \gets dist_{u, k} + dist_{k, v}distu,v←distu,k+distk,v
所以我们在Floyd迭代的过程中进行删边的判断即可,同时需要用一个set将边存起来用于判断哪些边是存在且可以删除的
代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector go(n + 1, std::vector<int>(n + 1, INF));
std::set<PII> edge;
for (int i = 1; i <= m; i ++) {
int u, v, w;
std::cin >> u >> v >> w;
go[u][v] = w;
go[v][u] = w;
edge.insert({std::min(u, v), std::max(u, v)});
}
for (int i = 1; i <= n; i ++) go[i][i] = 0;
std::set<PII> ans;
for (int k = 1; k <= n; k ++)
for (int u = 1; u <= n; u ++)
for (int v = 1; v <= n; v ++) {
if (go[u][v] >= go[u][k] + go[k][v] && u != k && v != k)
if (edge.contains({std::min(u, v), std::max(u, v)}))
ans.insert({std::min(u, v), std::max(u, v)});
go[u][v] = std::min(go[u][v], go[u][k] + go[k][v]);
}
std::cout << ans.size() << '\n';
}