题目大意:
给出 \(n(n \leq 300)\) 个节点的无向图联通图,问最多可以删除多少条边,使得删除后的图,对于任意两个节点 \(u\) 、\(v\) 其最短路都没有发生改变。
思路:
赛时以为是求 \(n\) 遍最短路,标记所有最短路上的边,然后剩下的就是可以删的,但是这样删很有可能删多了,也处理不了这样的情况:
3 3
1 2 2
2 3 3
1 3 5
还是考虑松弛操作,对于一条边 \([u, v]\) 来说,如果它被松弛了,则说明这条边不是最短路上的边,不需要留下,因为可以经过其他更短的边从 \(u\) 到达 \(v\)。
这题的 \(n\) 很小,我们可以使用 floyd 求出任意两点的最短路,然后枚举边判断该边是否被松弛过,累计可以删除的边。
Code:
struct Edge {
int u, v, w;
};
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1, vector<int>(n + 1, INF));
for (int i = 1; i <= n; i++) {
g[i][i] = 0;
}
vector<Edge> e(m);
for (int i = 0; i < m; i++) {
cin >> e[i].u >> e[i].v >> e[i].w;
g[e[i].u][e[i].v] = g[e[i].v][e[i].u] = e[i].w;
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
ckmin(g[i][j], g[i][k] + g[k][j]);
}
}
}
int cnt = 0;
for (auto [u, v, w] : e) {
bool ok = true;
for (int k = 1; k <= n; k++) {
if (k != u && k != v && g[u][v] >= g[u][k] + g[k][v]) {
ok = false;
}
}
cnt += ok;
}
cout << m - cnt << "\n";
return 0;
}