1. 程式人生 > >牛客國慶集訓派對Day3 I-Metropolis (迪傑斯特拉堆優化)

牛客國慶集訓派對Day3 I-Metropolis (迪傑斯特拉堆優化)

題目描述

魔方國有n座城市,編號為。城市之間通過n-1條無向道路連線,形成一個樹形結構。 在若干年之後,其中p座城市發展成了大都會,道路的數量也增加到了m條。 大都會之間經常有貿易往來,因此,對於每座大都會,請你求出它到離它最近的其它大都會的距離。

輸入描述:

第一行三個整數n,m,p (1 ≤ n,m ≤ 2*105,2 ≤ p ≤ n),第二行p個整數表示大都會的編號 (1≤ xi≤ n)。接下來m行每行三個整數ai,bi,li表示一條連線ai和bi,長度為li的道路 (1 ≤ ai,bi ≤ n,1 ≤ li ≤ 109)。
保證圖是連通的。

輸出描述:

輸出一行p個整數,第i個整數表示xi的答案。

示例1

輸入

複製

5 6 3
2 4 5
1 2 4
1 3 1
1 4 1
1 5 4
2 3 1
3 4 3

輸出

複製

3 3 5

解題思路:考慮暴力,求出兩點間的最短路徑,明顯不可取。但是題目只是要求某些點之間的最短路徑,考慮優化。我們從某一個要求的點出發,用迪傑斯特拉求最短路徑,第一個碰到的要求的點,就是該點的答案,我們記錄即可。我們對所有的點都做一遍這個操作,即可求得答案,但是這樣的複雜度感覺降低了(因為提前退出了迪傑斯特拉),實際上沒有降低。那麼我們考慮優化,我們用堆優化的迪傑斯特拉去求最短路,很容易就會想到,我們把所有要求的點在一開始就入隊,然後做一遍迪傑斯特拉即可,當碰到要求的點時我們更新最短路徑即可。這裡有兩種情況,一種是真的走到了要求的點,一種是走到了一半,這裡直接用染色的思想處理即可。

#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
typedef long long ll;
const int MAXN=2000005;
const ll INF=0x3f3f3f3f3f3f3f3f;

struct edge{
    int u;
    int v;
    int w;
    int next;
}e[MAXN];
int edge_num=0;
int head[MAXN];
void insert_edge(int u,int v,int w){
    e[edge_num].u=u;
    e[edge_num].v=v;
    e[edge_num].w=w;
    e[edge_num].next=head[u];
    head[u]=edge_num++;
}

struct node{
    int v;
    ll dis;
    node (ll a,int b):dis(a),v(b){};
    bool operator <(const node &rhs)const
    {
        return dis > rhs.dis;
    }
};

int N,M,K;
bool vis[MAXN];
int P[MAXN];
ll d[MAXN];
ll ans[MAXN];
int belong[MAXN];

void dijkstra(){
    priority_queue<node> que;
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    memset(ans,0x3f,sizeof(ans));
    for(int i=0;i<K;i++)
        que.push(node(d[P[i]]=0,P[i]));

    while(!que.empty()){
        node tp=que.top();
        que.pop();
        int u=tp.v;
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            int w=e[i].w;
            if(d[v]>d[u]+w)//如果碰到了,此條件必然不成立,因為初始為0
            {
                d[v]=d[u]+w;
                que.push(node(d[v],v));
                belong[v]=belong[u];//將從該點出發求最短路徑的過程都染色
            }else if(belong[u]!=belong[v])//如果不同顏色就更新答案
            {
                ans[belong[u]]=min(ans[belong[u]],d[u]+d[v]+w);
                ans[belong[v]]=min(ans[belong[v]],d[u]+d[v]+w);
            }
        }
    }
}

int main(){

    scanf("%d%d%d",&N,&M,&K);
    edge_num=0;
    memset(head,-1,sizeof(head));

    for(int i=0;i<K;i++){
        scanf("%d",&P[i]);
        belong[P[i]]=P[i];
    }

    int u,v,w;
    for(int i=0;i<M;i++){
        scanf("%d%d%d",&u,&v,&w);
        insert_edge(u,v,w);
        insert_edge(v,u,w);
    }
    dijkstra();

    for(int i=0;i<K;i++)
        printf("%lld ",ans[P[i]]);

    return 0;
}