题解:洛谷 P5683 [CSP-J2019 江西] 道路拆除

洛谷 P5683 [CSP-J2019 江西] 道路拆除

题意

有一个 \(n\) 个点 \(m\) 条边的无向图,边权均为 \(1\)

要求删除一些边,使得 \(1\leadsto s_1\) 的长度 \(\le t_1\)\(1\leadsto s_2\) 的长度 \(\le t_2\)

无解输出 \(-1\)

\(n,m\le3\times10^3\)

解法

无解的情况很好判断,只要初始图中就无法满足条件即可,否则必然有解。


转化为保留最少的边。

显然最后剩余的边必然形成一颗树,保留了 \(1\leadsto s_1\)\(1\leadsto s_2\) 的路径。

考虑两条路径最后一个相同点 \(i\),枚举 \(i\) 即可。

枚举点 \(i\),然后统计三条边的最短路即可。

由于是无向图,所以可以转化为端点到某一点的距离,那么就可以用 BFS 预处理了。

答案如下,但是要满足 \(t\) 的限制。

\[m-\min\limits_{i=1}^{n}\left\{w(1,i)+w(s_1,i)+w(s_2,i)\right\} \]

时间复杂度

  • 预处理距离,\(O(n+m)\)
  • 枚举每一个点并计算,\(O(n)\)

时间复杂度 \(O(n+m)\),可以通过。

细节证明

"最后剩余的边必然形成一颗树"。

那么最后剩余的边会不会有环呢?

假设最后剩余的边有环,那么我们只需要保留其与树的交集。由于边权为 \(1\),所以经过边数越多权值越大。

这样就又变回了一颗树。

代码

/**
 * Problem: P5683 [CSP-J2019 江西] 道路拆除
 * Author:  OIer_wst
 * Date:    2025-06-30
 */
#include <bits/stdc++.h>
using lint = long long;
const int N = 3e3 + 10;
const int INF = 0x3f3f3f3f;

int hh, tt, q[N];

std::vector<int> g[N];
int n, m, ans = -1, s1, t1, s2, t2, dis[3][N];

void bfs(int x, int dis[]) {
  memset(dis, 0x3f, N << 2);
  hh = tt = 0, q[0] = x, dis[x] = 0;
  while (hh <= tt) {
    int u = q[hh++];
    for (auto v : g[u]) {
      if (dis[v] == INF) {
        dis[v] = dis[u] + 1;
        q[++tt] = v;
      }
    }
  }
}

int main() {
  std::cin >> n >> m;
  for (int i = 0, u, v; i < m; ++i) {
    std::cin >> u >> v;
    g[u].emplace_back(v);
    g[v].emplace_back(u);
  }
  std::cin >> s1 >> t1 >> s2 >> t2;
  bfs(1, dis[0]), bfs(s1, dis[1]), bfs(s2, dis[2]);
  for (int i = 1; i <= n; ++i) {
    if (dis[0][i] + dis[1][i] <= t1 && dis[0][i] + dis[2][i] <= t2) {
      ans = std::max(ans, m - dis[0][i] - dis[1][i] - dis[2][i]);
    }
  }
  std::cout << ans << std::endl;
  return 0;
}

模型归纳

将路径拆分成几个端分别解决。

类似题目:

技巧

正难则反,将「最大化删除」转化为「最小化保留」,从而使题目的思考变得容易。

posted @ 2025-06-30 21:07  OIer_wst  阅读(42)  评论(0)    收藏  举报