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

Link

给定一个 \(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;
}
posted @ 2021-08-11 10:45  recollector  阅读(138)  评论(0编辑  收藏  举报