AtCoder Beginner Contest 243 E - Edge Deletion(Floyd)

每周至少五篇博客:(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) 而言, sssttt 之间的最短距离在删除前后保持不变。

思路

首先如果我们有上述的三条边 u→k,u→v,k→vu \rightarrow k, u \rightarrow v, k \rightarrow vuk,uv,kv 并且满足 distu,v≥distu,k+distk,vdist_{u, v} \ge dist_{u, k} + dist_{k, v}distu,vdistu,k+distk,v,那么 u→vu \rightarrow vuv 这条边是可以删除的

看到数据范围很小,并且这里是每个点到其他点的最短路长度,所以应该想到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,vdistu,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';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值