多源最短路 Metropolis
题目大意:给一张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;
}