CF1320B Navigation System(最短路)

Description

给定一个 n n n 个点 m m m 条边的有向图,和一个长度为 k k k 的起点终点确定的路径 p p p。从 p 1 p_1 p1 p t p_t pt,如果路径上的一个点不在最短路上,那么导航次数多一次,导航不会影响路径。求最少和最多的导航次数。

2 ≤ n , m ≤ 2 × 1 0 5 2 \leq n,m \leq 2 \times 10^5 2n,m2×105

Solution

先跑从 t t t 出发的 bfs,这个要建出反向边。如果从最短路上的一个点 x x x 出发,下一个走的点为 y y y 还在最短路上当且仅当 d i s y = d i s x − 1 dis_y = dis_x - 1 disy=disx1。所以从 s s s 走,分类讨论

  • d i s p i = d i s p i − 1 − 1 dis_{p_i} = dis_{p_{i-1}} - 1 dispi=dispi11。那么最少次数和上次相等。如果从 k i k_i ki 走还有满足最短路的其他点,那么最多可以多一次。

  • d i s p i ≠ d i s p i − 1 − 1 dis_{p_i} \not= dis_{p_{i-1}} - 1 dispi=dispi11。一定要重新规划了,最小和最大都多一次。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5, M = 5e5 + 5, INF = 0x3f3f3f3f;
inline int read() {
	int x = 0, f = 0; char ch = 0;
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}
struct edge{
    int to, nxt;
}e[M]; 
int head[N], tot;
void addedge(int x, int y) {
    e[++tot].to = y, e[tot].nxt = head[x], head[x] = tot;
}
int n, m, k;
int p[N], dis[N]; 
void bfs(int s) {
	queue <int> q;
	dis[s] = 1; q.push(s);
	while (!q.empty()) {
		int x = q.front(); q.pop();
		for (int i = head[x]; i; i = e[i].nxt) {
			int y = e[i].to;
			if (!dis[y]) {
				dis[y] = dis[x] + 1;
				q.push(y);
			}
		}
	}
}
int ex[N], ey[N];
int main() {
	n = read(), m = read();
	for (int i = 1; i <= m; i++) {
		ex[i] = read(); ey[i] = read();
		addedge(ey[i], ex[i]);
	}
	k = read();
	for (int i = 1; i <= k; i++) p[i] = read();
	bfs(p[k]);
	int mn = 0, mx = 0;
	memset(head, 0, sizeof(head)); tot = 0;
	for (int i = 1; i <= m; i++) addedge(ex[i], ey[i]);
	for (int i = 1; i < k; i++) {
		if (dis[p[i]] != dis[p[i + 1]] + 1) mn++, mx++;
		else {
			for (int j = head[p[i]]; j; j = e[j].nxt) {
				int y = e[j].to;
				if (dis[y] == dis[p[i + 1]] && y != p[i + 1]) {
					mx++; break;
				}
			}
		}
	}
	printf("%d %d\n", mn, mx);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值