题目链接:http://acm.uestc.edu.cn/#/problem/show/1639
题意:
在n个点m条边的无向图上,有k个出口
从起点出发,每到一个点(包括起点),该点连出的边中有d条会被封锁
求最坏情况下到达出口的最短路
数据范围:
1<=n<=100000
1<=m<=1000000
题解:
Dijkstra拓展
由于求最坏情况下的最短路,对于每个点,显然最优的前d条边不能走。
对于边u->v,必然要先得到v到出口的最坏情况下的最短路才能得到u经过该边再到出口的最坏情况下的最短路,
也就是该边对于u的价值,所以要从出口往回考虑。
令f[i]表示i到出口的最坏情况下的最短路,同dijkstra算法一样,每个点i可以分为f[i]已确定的和f[i]未确定的
初始时自然是对于每个出口x,f[x]=0已确定。
对于f[v]已确定的点v,将边权为w的边u->v以f[v]+w为关键字加入小根堆中。
对于每个点i还要记录cnt[i]=k,表示到i后,i连出的最优的前k条边已被封锁。
每次取出堆顶对应的边u->v(若f[u]已确定直接弹出)则该边为u连出的(除已被封锁的边外)最优的边
若cnt[u]
//UESTC 1639
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
const int maxm = 1e6+7;
const int inf = 0x3f3f3f3f;
vector <pair<int,int> > G[maxn];
int dis[maxn], vis[maxn], cnt[maxn];
priority_queue <pair<int,int>, vector<pair<int, int> > , greater<pair<int, int> > >pq;
int u, v, w, k, d, n, m, len;
void Dij()
{
memset(vis, 0, sizeof(vis));
while(!pq.empty()){
u = pq.top().second;
w = pq.top().first;
pq.pop();
if(vis[u]) continue;
if(cnt[u] == d){
dis[u] = w;
vis[u] = 1;
}
else{
cnt[u]++;
continue;
}
for(int i = 0; i < (int)G[u].size(); i++){
v = G[u][i].second;
len = G[u][i].first;
if(dis[v] > len + w){
pq.push(make_pair(len+w, v));
}
}
}
}
int main()
{
while(~scanf("%d %d %d %d", &n,&m,&k,&d))
{
while(!pq.empty()) pq.pop();
for(int i=0; i<=n; i++) dis[i]=inf;
memset(cnt, 0, sizeof(cnt));
for(int i=0; i<maxn; i++) G[i].clear();
for(int i=1; i<=m; i++){
scanf("%d %d %d", &u,&v,&w);
G[u].push_back(make_pair(w, v));
G[v].push_back(make_pair(w, u));
}
while(k--){
scanf("%d", &u);
cnt[u] = d;
dis[u] = 0;
pq.push(make_pair(0, u));
}
Dij();
if(dis[0]==inf) dis[0]=-1;
printf("%d\n", dis[0]);
}
return 0;
}