AtCoder Beginner Contest 243 E - Edge Deletion(最短路)

E - Edge Deletion

题目大意:

给出 \(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;
}
posted @ 2022-03-13 20:03  Nepenthe8  阅读(113)  评论(0编辑  收藏  举报