CF1320B Navigation System

CF1320B Navigation System

题目描述

Bertown 的地图可以表示为 \(n\) 个路口,编号从 \(1\) 到 \(n\),通过 \(m\) 条单向道路连接。可以通过这些道路从任意一个路口到达另一个路口。从一个路口到另一个路口的某条路径的长度是沿该路径需要经过的道路数。从路口 \(v\) 到路口 \(u\) 的最短路径是所有从 \(v\) 到 \(u\) 的路径中长度最短的那一条。

Polycarp 住在路口 \(s\) 附近,在路口 \(t\) 附近的建筑物工作。每天他都会开车从 \(s\) 到 \(t\)。今天他选择了如下路径去上班:\(p_1, p_2, \ldots, p_k\),其中 \(p_1 = s\),\(p_k = t\),其余元素为中间经过的路口,按 Polycarp 到达它们的顺序排列。Polycarp 从不重复经过同一个路口,因此该序列中的所有元素两两不同。注意,你事先知道 Polycarp 的路径(它是固定的),且这条路径不一定是 \(s\) 到 \(t\) 的最短路径之一。

Polycarp 的汽车上安装了一个复杂的导航系统。其工作方式如下:当 Polycarp 从路口 \(s\) 出发时,系统会选择一条从 \(s\) 到 \(t\) 的最短路径,并将其显示给 Polycarp。我们记该路径上的下一个路口为 \(v\)。如果 Polycarp 按照系统推荐的道路从 \(s\) 到 \(v\),那么导航系统会继续显示同一条最短路径(显然,从 \(v\) 开始显示剩下的部分)。但如果 Polycarp 选择前往另一个路口 \(w\),那么导航系统会重新规划路径:一旦 Polycarp 到达 \(w\),系统会选择一条从 \(w\) 到 \(t\) 的最短路径并显示给他。这个过程会一直持续到 Polycarp 到达 \(t\):如果 Polycarp 沿着系统推荐的道路行驶,系统就保持当前的最短路径;如果他选择其他道路,系统就按上述规则重新规划。

下面是一个例子。假设 Bertown 的地图如下,Polycarp 按路径 \([1, 2, 3, 4]\) 行驶(\(s = 1\),\(t = 4\)):

请查看图片链接 http://tk.codeforces.com/a.png

  1. 当 Polycarp 从 \(1\) 出发时,系统选择一条从 \(1\) 到 \(4\) 的最短路径。这里只有一条,即 \([1, 5, 4]\);
  2. Polycarp 选择前往 \(2\),这不在系统选择的路径上。当 Polycarp 到达 \(2\) 时,导航系统重新规划路径,选择一条从 \(2\) 到 \(4\) 的最短路径,例如 \([2, 6, 4]\)(注意也可以选择 \([2, 3, 4]\));
  3. Polycarp 选择前往 \(3\),这也不在系统选择的路径上。当 Polycarp 到达 \(3\) 时,导航系统重新规划路径,选择唯一的最短路径 \([3, 4]\);
  4. Polycarp 沿着导航推荐的道路到达 \(4\),因此系统无需重新规划。

总的来说,这种情况下一共发生了 \(2\) 次重新规划。注意,如果系统在第二步选择的是 \([2, 3, 4]\),那么只会有 \(1\) 次重新规划(因为 Polycarp 沿着路径前进,系统会在第三步保持 \([3, 4]\))。

这个例子说明,即使 Bertown 的地图和 Polycarp 选择的路径相同,重新规划的次数也可能不同。给定这些信息(地图和 Polycarp 的路径),你能否确定在旅途中可能发生的最小和最大重新规划次数?

输入格式

第一行包含两个整数 \(n\) 和 \(m\)(\(2 \le n \le m \le 2 \cdot 10^5\)),分别表示 Bertown 的路口数和单向道路数。

接下来 \(m\) 行,每行描述一条道路。每行包含两个整数 \(u\) 和 \(v\)(\(1 \le u, v \le n\),\(u \ne v\)),表示一条从路口 \(u\) 到路口 \(v\) 的道路。Bertown 的所有道路两两不同,即每个有序对 \((u, v)\) 最多只出现一次(但如果有 \((u, v)\),也可能有 \((v, u)\))。

接下来一行包含一个整数 \(k\)(\(2 \le k \le n\)),表示 Polycarp 从家到单位路径经过的路口数。

最后一行包含 \(k\) 个整数 \(p_1, p_2, \ldots, p_k\)(\(1 \le p_i \le n\),这些整数两两不同),表示 Polycarp 路径上依次经过的路口。\(p_1\) 是 Polycarp 的住处(\(s = p_1\)),\(p_k\) 是 Polycarp 的单位(\(t = p_k\))。保证对于每个 \(i \in [1, k-1]\),都存在从 \(p_i\) 到 \(p_{i+1}\) 的道路,即该路径沿 Bertown 的道路行驶。

输出格式

输出两个整数:在旅途中可能发生的最小和最大重新规划次数。

输入输出样例 #1

输入 #1

6 9
1 5
5 4
1 2
2 3
3 4
4 1
2 6
6 4
4 2
4
1 2 3 4

输出 #1

1 2

输入输出样例 #2

输入 #2

7 7
1 2
2 3
3 4
4 5
5 6
6 7
7 1
7
1 2 3 4 5 6 7

输出 #2

0 0

输入输出样例 #3

输入 #3

8 13
8 7
8 6
7 5
7 4
6 5
6 4
5 3
5 2
4 3
4 2
3 1
2 1
1 8
5
8 7 5 2 1

输出 #3

0 3

说明/提示

由 ChatGPT 4.1 翻译

算法分析

这道题说真的就是考验码力,首先,要有耐心完整的读完题面并理解,然后思路就是模板了,由于有很多条路经,所以可以建反图,遍历每条边满不满足条件就可以了,就是求两点最短路,因为边权为\(1\),所以可以\(bfs\),但作者觉得最短路更好写,所以最短路。

#include<bits/stdc++.h>
using namespace std;
struct node{
	int x,y;
};
int n,m,k;
int mn = 0;
int mx = 0;
bool vis[200005];
node c[200005];
int a[200005];
int b[200005];
vector<int> e1[200005];
vector<int> e2[200005];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
void dijkstra(){//dijkstra堆优化模板
	memset(b,0x3f3f3f3f,sizeof(b));
	b[a[k]] = 0;
	pq.push(make_pair(0,a[k]));
	while(!pq.empty()){
		int pos = pq.top().second;
		pq.pop();
		if(vis[pos]){
			continue;
		}
		vis[pos] = 1;
		for(auto i : e2[pos]){
			if(b[i]>b[pos]+1){
				b[i] = b[pos]+1;
				pq.push(make_pair(b[i],i));
			}
		}
	}
} 
int main(){
	cin>>n>>m;
	for(int i = 1; i<=m; i++){
		int x,y;
		cin>>x>>y;
		e1[x].push_back(y);
		e2[y].push_back(x);//建反图
	}
	cin>>k;
	for(int i = 1; i<=k; i++){
		cin>>a[i];
	}
	dijkstra();//最短路
	for(int i = 1; i<k; i++){
		int x = a[i];
		int y = a[i+1];
		if(b[x]!=b[y]+1){//非等价
			mn++;
			mx++;
		}else{
			for(auto j : e1[x]){//遍历原图
				if(b[j]==b[x]-1 && j!=y){
					mx++;
					break;
				}
			}
		}
	}
	cout<<mn<<" "<<mx;
	return 0;
}

总结

一道板子,难就难在阅读题面上,总之就是模板题。

posted @ 2026-09-26 22:46  xmgene  阅读(3)  评论(0)    收藏  举报