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