多源最短路 Metropolis

牛课周周练 12 B

传送门

题目大意:给一张n个点,m条边的无向图(n<=2e5,m<=2e5)。现在给一些关键点,找一下离这些关键点最近的一个关键点,并且输出距离。

分析:考虑到多源最短路\(floyd\)的复杂度的复杂度高达\(O(n^3)\),肯定是不能跑这个算法的。从小到大考虑所有关键点到其他点的距离:对于每一个点需要记录一下是哪一个关键点到这里的,距离是多少。这样的话每一个关键点,搜索时总会在另一个关键点处,或者是被另一个关键点最近的点卡住。这样的话,正确性是显然的,并且复杂度也能接受。

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const LL inf = (1ll)<<60;

const int N = 200005;

struct Node{
    int x, y;
    LL val;
    bool operator<(const Node& a)const{
        return val>a.val;
    }
};

priority_queue<Node> q;

LL d[N], ans[N];

int mark[N];

int head[N], Next[N<<1], weight[N<<1], to[N<<1], tot;

void add_edge(int u, int v, int w){
    Next[++tot]=head[u];head[u]=tot;to[tot]=v;weight[tot]=w;
    Next[++tot]=head[v];head[v]=tot;to[tot]=u;weight[tot]=w;
}

int st[N], top;
int n, m;

inline void chmin(LL& x, LL y){x=min(x,y);}

void dij(){
    for(int i=1;i<=n;++i){
        d[i]=ans[i]=inf;
    }

    for(int i=1;i<=top;++i){
        q.push((Node){st[i],st[i],0ll});
    }

    while(!q.empty()){
        Node t=q.top();
        q.pop();

        int u=t.x,v=t.y;
        LL val=t.val;

        if(!mark[v]){
            mark[v]=u;
            d[v]=val;

            for(int e=head[v];e;e=Next[e]){
                int tv=to[e];
                q.push((Node){u,tv,val+weight[e]});

            }
        }else if(mark[v]!=u){
            chmin(ans[u],val+d[v]);
            chmin(ans[mark[v]],val+d[v]);
        }
    }
}

int main(){
    scanf("%d%d%d", &n, &m, &top);
    for(int i=1;i<=top;++i)scanf("%d",st+i);

    for(int i=1;i<=m;++i){
        int u, v, w;
        scanf("%d%d%d", &u,&v,&w);
        add_edge(u,v,w);
    }

    dij();

    for(int i=1;i<=top;++i)printf("%lld ",ans[st[i]]);
    printf("\n");


    return 0;
}

posted @ 2020-06-24 16:43  John_Ran  阅读(134)  评论(0编辑  收藏  举报