牛客国庆集训派对day3——I(多源最短路)


题目描述:

链接: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的答案。

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

示例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

很明显的一个多源最短路问题,我们熟悉的多源最短路就是floyd算法,但是floyd在这题中肯定超时,因为n<=2e5,floyd的O(n^3)肯定做不了。所以我们另寻捷径。

将所有大都市都看作源点跑多源最短路,并记录下每个节点是由哪个源点的最短路扩展而来。如果源点i从出发走到了点k,而点k也可以由另一个源点j扩展而来,那么肯定这条路就是从i到j的最短路,就没有必要再扩展下去了。总结来说就是,如果一条边的两端点由两个不同的源点扩展而来,那么这条边一定就是这两个源点的最短路中的一条,更新答案即可。

具体细节看代码:

注意要把inf设置成0x3f3f3f3f3f3f3f3f,这提数据很大,之前inf设小了wa了好多发

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

typedef long long ll;
const int maxn=2e5+10;
const ll INF=0x3f3f3f3f3f3f3f3f;
struct Edge{
    int u;
    int v;
    ll w;
    Edge(int _u=0,int _v=0,ll _cost=0):u(_u),v(_v),w(_cost){}
};
vector<int>G[maxn];
vector<Edge>edges;
void init(int n)
{
    for(int i=0;i<=n;i++)G[i].clear();
    edges.clear();
}
void add_edges(int u,int v,ll w)
{
    edges.push_back(Edge(u,v,w));
    edges.push_back(Edge(v,u,w));
    int m=edges.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}
struct HeapNode
{
    ll d;
    int u;
    HeapNode(ll _d=0,int _u=0):d(_d),u(_u){}
    bool operator < (const HeapNode &rhs)const
    {
        return d>rhs.d;
    }
};

ll dist[maxn];
int from[maxn];//点是由哪个源点扩展的
int vis[maxn];
ll ans[maxn];//两个源点之间的最短路
int c[maxn];//源点编号
void dijkstra(int n,int p)
{
    priority_queue<HeapNode>Q;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)dist[i]=INF;
    for(int i=1;i<=n;i++)ans[i]=INF;
    while(!Q.empty())Q.pop();
    for(int i=1;i<=p;i++)
        Q.push(HeapNode(dist[c[i]]=0,c[i]));
    while(!Q.empty())
    {
        HeapNode temp=Q.top();Q.pop();
        int u=temp.u;
        if(vis[u])continue;
        vis[u]=1;
        for(int i=0;i<G[u].size();i++)
        {
            Edge &e=edges[G[u][i]];
            int v=e.v;
            if(dist[v]>dist[u]+e.w)
            {
                dist[v]=dist[u]+e.w;
                Q.push(HeapNode(dist[v],v));
                from[v]=from[u];//表示这条边的最短路是被同一个源点扩展的
            }
            else if(from[v]!=from[u])//一条边由两个不同的源点扩展,一定是最短路
            {
                ans[from[v]]=min(ans[from[v]],dist[u]+dist[v]+e.w);
                ans[from[u]]=min(ans[from[u]],dist[u]+dist[v]+e.w);
            }
        }
    }
}


int main()
{
    int n,m,p;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        init(n);
        for(int i=1;i<=p;i++)
        {
            scanf("%d",&c[i]);
            from[c[i]]=c[i];//每个大都市的起点都是他自己
        }
        for(int i=1;i<=m;i++)
        {
            int x,y;
            ll w;
            scanf("%d%d%lld",&x,&y,&w);
            add_edges(x,y,w);
        }
        dijkstra(n,p);
        for(int i=1;i<=p;i++)
        {
            if(i!=p)
                printf("%lld ",ans[c[i]]);
            else
                printf("%lld\n",ans[c[i]]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Q755100802/article/details/82952150