题解 P5683 [CSP-J2019 江西] 道路拆除
给定一个 \(n\) 个点 \(m\) 条边的无向图,求两条路径 \(1\to s_1,1 \to s_2\) ,使得两条路径的长度分别不大于 \(t_1,t_2\) ,且两条路径用到的所有边的总数量最少。你需要输出 \(m\) 减用到的边数
\(1 \leq n,m \leq 3\times 10^3\) 。
考场上乱搞拿了 35pts
首先,如果直接求 \(1\) 到这两个点的最短路,然后求这两条最短路用到的边的总数是不对的,因为如果公共部分多一点,可能会更优。
经过一段时间的观察,我们容易发现:公共部分一定是一条连续的链,因为如果链的中间断开了,那么把更长的那一条变成更短的那一条,路径长度变少了,公共部分变长了,肯定更优。
于是就可以枚举这个分界点 \(k\) ,这两条路径就被拆成了三条互不相关的路径 \(1\to k ,k \to s_1 ,k \to s_2\) ,答案最小意味着这三条路径都是最短路。
于是从 \(1,s_1,s_2\) \(bfs\) 三次,就可以求出这三条最短路的长度了( \(k \to s_1\) 在无向图中的最短路径长度等于 \(s_1\to k\) 的最短路径长度。)
注意枚举 \(1\to k \to s_1\) 的长度 \(\leq t_1\) , \(1 \to k \to s_2\) 的长度 \(\leq t_2\) 。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
inline int read() {
int num = 0 ,f = 1; char c = getchar();
while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar();
while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar();
return num * f;
}
const int N = 3e3 + 5 ,M = 6e3 + 5 ,INF = 0x3f3f3f3f;
struct Edge {
int to ,next;
Edge (int to = 0 ,int next = 0) : to(to) ,next(next) {}
}G[M]; int head[N] ,idx;
inline void add(int u ,int v) {
G[++idx] = Edge(v ,head[u]); head[u] = idx;
G[++idx] = Edge(u ,head[v]); head[v] = idx;
}
int n ,m ,t1 ,t2 ,A ,B;
inline void bfs(int s ,int dis[]) {
for (int i = 1; i <= n; i++) dis[i] = INF;
queue <int> q;
q.push(s); dis[s] = 0;
while (!q.empty()) {
int now = q.front(); q.pop();
for (int i = head[now]; i ; i = G[i].next) {
int v = G[i].to;
if (dis[v] == INF) {
dis[v] = dis[now] + 1;
q.push(v);
}
}
}
}
int dis1[N] ,dis2[N] ,dis3[N];
signed main() {
n = read() ,m = read();
for (int i = 1; i <= m; i++) {
int u = read() ,v = read();
add(u ,v);
}
A = read() ,t1 = read() ,B = read() ,t2 = read();
bfs(1 ,dis1);
bfs(A ,dis2);
bfs(B ,dis3);
int ans = INF;
for (int i = 1; i <= n; i++)
if (dis1[i] + dis2[i] <= t1 && dis1[i] + dis3[i] <= t2)
ans = min(ans ,dis1[i] + dis2[i] + dis3[i]);
//这里就算三条路径有重复也没关系,因为如果有重复意味着在别的分界点有更优的答案
if (ans == INF) puts("-1");
else printf("%d\n" ,m - ans);
return 0;
}