牛客国庆集训派对Day3 I-Metropolis (迪杰斯特拉堆优化)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/82933600

链接:https://www.nowcoder.com/acm/contest/203/I
来源:牛客网
 

题目描述

魔方国有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;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/82933600