acwing 1137. 选择最佳线路

题目传送门

题目描述

有一天,琪琪想乘坐公交车去拜访她的一位朋友。

由于琪琪非常容易晕车,所以她想尽快到达朋友家。

现在给定你一张城市交通路线图,上面包含城市的公交站台以及公交线路的具体分布。

已知城市中共包含 nn 个车站(编号11~nn)以及 mm 条公交线路。

每条公交线路都是 单向的,从一个车站出发直接到达另一个车站,两个车站之间可能存在多条公交线路。

琪琪的朋友住在 ss 号车站附近。

琪琪可以在任何车站选择换乘其它公共汽车。

请找出琪琪到达她的朋友家(附近的公交车站)需要花费的最少时间。

输入格式

输入包含多组测试数据。

每组测试数据第一行包含三个整数 n,m,sn,m,s,分别表示车站数量,公交线路数量以及朋友家附近车站的编号。

接下来 mm 行,每行包含三个整数 p,q,tp,q,t,表示存在一条线路从车站 pp 到达车站 qq,用时为 tt。

接下来一行,包含一个整数 ww,表示琪琪家附近共有 ww 个车站,她可以在这 ww 个车站中选择一个车站作为始发站。

再一行,包含 ww 个整数,表示琪琪家附近的 ww 个车站的编号。

输出格式

每个测试数据输出一个整数作为结果,表示所需花费的最少时间。

如果无法达到朋友家的车站,则输出 -1。

每个结果占一行。

数据范围

n≤1000,m≤20000n≤1000,m≤20000,
1≤s≤n1≤s≤n,
0<w<n0<w<n,
0<t≤10000<t≤1000

输入样例:

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

输出样例:

1
-1

反向建图+Dijkstra最短路

分析

首先反向建图

然后从终点s进行dijkstra

然后在w个出发点中选择dist[]最小的出发就行


这个的原理就是:

如果从a出发经过最短路到达b,那么从b出发经过同样的最短路就可以到a


注意:****对每组数据,要把上次使用的图信息h[n]清除掉,而且需要将st数组初始化成false

代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring> 
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
const int INF = 0x3f3f3f3f;

int dist[N]; // 从1到每个点的最短距离 
bool st[N]; // 每个点是否出现过 
int n, m, s;
int w;

// 一个点和边权
struct VER
{
	int to;
	int w;	
}; 
vector<VER> h[N];
// a->b 边权是w 
void add(int a, int b, int w)
{
	VER ver;
	ver.to = b;
	ver.w = w;
	h[a].push_back(ver); 
} 
// 定义图 

// 从s开始搜 
void dijkstra(int s)
{
	// 初始化所有点的最小距离为INF,1的最小距离为0 
	memset(dist, 0x3f, sizeof dist);
	dist[s] = 0;
	
	priority_queue< PII, vector<PII>, greater<PII> > heap; //定义小根堆 
	heap.push({0,s}); // {distance, ver} push到堆里的是一个pair,第一个是到该点的最短距离,第二个是该点的编号,
				       // 因为优先队列按照第一个排序 
	// 每次不continue的时候确定一个点的最小距离 
	while(heap.size())
	{
		PII t = heap.top();
		heap.pop();
		int distance = t.first, ver = t.second;
		
		if(st[ver]) continue; // 因为一个点的距离会被放入堆多次,只需要取一次最小的就行
		st[ver] = true; // 确定了该点的最小距离 
		 
		// 遍历ver指向的所有点j 
		for(int i = 0; i < h[ver].size(); i++)
		{
			int j = h[ver][i].to;
			int w = h[ver][i].w;
			// 如果j没被确定最小距离,并且可以更新的话
                // 就更新j的最短距离,同时加入堆	
			if(dist[j] > distance + w)
			{
				dist[j] = distance + w;
				heap.push({dist[j], j}); //dist[j]会被放入多次,会有冗余,只需要取最小的那个就行 
			}
		}
		
	}

}

// 每次使用dijkstra之前先初始化 
void init()
{
	for(int i = 1; i <= n; i++) h[i].clear();
	memset(st, 0, sizeof st);
}

int main()
{
	while(cin >> n >> m >> s)
	{
		init();
		// 反向建立边 
		for(int i = 0; i < m; i++)
		{
			int a, b, t;
			scanf("%d%d%d", &a, &b, &t);
			add(b, a, t); // 反向建边	
		} 
		
		dijkstra(s);
		
		scanf("%d", &w);
		int res = INF;
		for(int i = 0; i < w; i++)
		{
			int t;
			scanf("%d", &t);
			res = min(res, dist[t]);
		}
		if(res == INF) printf("-1\n");
		else		   printf("%d\n", res); 
	}
}	

时间复杂度

参考文章

https://www.acwing.com/solution/content/15865/

posted @ 2022-03-09 11:40  VanHope  阅读(26)  评论(0编辑  收藏  举报