题目链接: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;
}