题目描述
小赖走进了一个非常奇怪的迷宫。这个迷宫可以抽象出 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吧。
意会和类比很重要。