【dijkstra求k短路详解】迷宫

版权声明: https://blog.csdn.net/qq_38234381/article/details/81939994

题目描述

小赖走进了一个非常奇怪的迷宫。这个迷宫可以抽象出 n 个节点和 m 条无向 道路。节点编号从 0 到 n-1 进行编号,每条道路都有它的长度。一开始,你在 0 号节点。这个迷宫总共有 k 个出口,分别是 p1,p2……pk。小赖只要任意到达一 个出口就可以走出迷宫。不过,当她在某个节点时,会有不超过 d 条以这个节点 为一端的道路被封锁。被封锁的道路是随机产生的,你多次到达同一个节点时, 被封锁的道路可能会有所不同。 小赖现在想知道:在最坏情况下,她走出迷宫的最短路径的长度为多少?

输入输出格式

输入格式:

输入文件为escape.in 第一行为4个正整数n,m,k,d 接下来m行,每行三个正整数u,v,dis,描述一条无向道路,dis表示距离 最后一行有k个整数,为k个出口

输出格式:

输出文件为escape.out 一行一个整数,表示最坏情况下走出迷宫的最短路径的长度。如果最坏情况下 走不出迷宫,输出-1

输入输出样例

输入样例#1:

3 4 1 1
0 1 1
0 1 2
1 2 1
1 2 2
1

输出样例#1:

2

说明

【数据规模和约定】 对于50%的数据,满足m=n-1,且为连通图 对于90%的数据,满足n<=1000,m<=100000 对于100%的数据,满足n<=100000,m<=1000000,d<=3,k<n,且道路长度均为正整 数,保证答案不超过10^9

----------------------------------------------------------------------------------------------------------------------------------------------------------

题目可以转化为求第d+1短路,由于从起点向多个终点跑比较麻烦,所以干脆从终点向起点。

下面详细介绍用dijkstra(heap)求第d+1短路:

dijkstra算法在求最短路中,一个点出队的第一次它的最短路就已经确定,因为此时这条路是最短的,在没有负边的图中再也不可能通过其它边使其变得更短,这是其正确性的证明。那么,同样的,一个点在第d+1次出队就代表它的第d+1短路已经确定,这是第一个需要注意的地方。

其次是dijkstra中真正确定最短路的是上面所说的操作,而松弛只是提供辅助而已(或者说为后面的选择提供参考)。在这个问题中,由于我们已不是求最短路,所以松弛时不能用只取小的办法,前面也说过松弛只是提供参考,所以应使这个参考尽可能准确,即只要dis是INF,那么我们就松弛,可以意会一下。

最后需要注意的就是松弛时不能把dis赋值,因为这里dis的不一定是当前第d+1短路(在求最短路时,dis由于是最短路的估计值,所以可以赋值,这里的估计值就是当前最短的路)。如果赋值,则可能会导致后面以这个点为基值松弛时出现错误。

code:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

typedef pair<int, int> pii;
const int N = 1e5+10, M = 1e6+10, INF = 0x3f3f3f3f;
struct edge{
	int v, w, next;
} e[M<<1];
priority_queue<pii, vector<pii>, greater<pii> > Q;
int n, m, k, d, dis[N], count[N];
int cnt, head[N];

void init() {
	memset(head, -1, sizeof(head));
	memset(dis, INF, sizeof(dis));
	return ;
}

void add(int a, int b, int c) {
	e[++cnt].v = b;
	e[cnt].w = c;
	e[cnt].next = head[a];
	head[a] = cnt;
	return ;
}

void dijkstra() {
	int i;
	while(!Q.empty()) {
		pii temp = Q.top();
		Q.pop();
		int u = temp.second;
		if (count[u] > d+1) continue;
		else {
			count[u]++;
			if (count[u]==d+1 || !dis[u]) {
				dis[u] = temp.first;
				for (i = head[u]; i+1; i = e[i].next) {
					int v = e[i].v, w = e[i].w;
					if (dis[v] == INF) {
						pii temps = make_pair(dis[u]+w, v);
						Q.push(temps);
					}
				}
			}
		} 
	}
	return ;
} 

int main() {
	int i, x, y, z;
	init();
	scanf("%d%d%d%d", &n, &m, &k, &d);
	for (i = 1; i <= m; i++) {
		scanf("%d%d%d", &x, &y, &z);
		add(x, y, z);
		add(y, x, z);
	}
	int from;
	for (i = 1; i <= k; i++) {
		scanf("%d", &from);
		dis[from] = 0;
		pii temp = make_pair(dis[from], from);
		Q.push(temp); 
	}
	dijkstra();
	if (dis[0] == INF) printf("-1"); 
	else printf("%d", dis[0]);
	return 0;
}

另外,跑的比较慢,用cin的话大约要跑1.5秒左右,优化得当的话应该可以1s吧。

意会和类比很重要。

猜你喜欢

转载自blog.csdn.net/qq_38234381/article/details/81939994