HDU2680 (超级源点多起点最短路)
题目:https://acm.hdu.edu.cn/showproblem.php?pid=2680
题意:多个起点到终点的最短路的最短距离
最开始是用反向建图,跑一个dij,然后枚举找到多个起点的最短距离,时间复杂度为:一个dij+枚举n个起点。
更优化的能用超级源点,时间复杂度能优化到一个dij。
超级源点就是创建一个点0点,然后从0点建边到所有起点,权值为0,然后将0点作为新的起点,跑一个dij。因为0作为新起点,下一步一定就是走原来的各个起点,最后dis[终点]就是0点到终点的最短路径,但是0点到各个起点的权值设为的0,相当于并没有算0点到其中某一个起点(dis[终点]肯定只是经过了其中一个起点)的权值。
//

点击查看代码
//超级源点(时间复杂度为一个最短路。反向建图,是一个最短路+枚举n)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e4+9;
int n,m,s,Min=N;
vector<pair<int,int>>G[N];//first:存值
vector<int>dis(N,N),vis(N,0);
void dij(int st){//st:起点
priority_queue<pair<int,int>>q;//q.first:存起点到second点当前要用的最短路程
q.push({0,st});
dis[st]=0;
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto[x,y]:G[u]){//u--->y
if(dis[y]>dis[u]+x){//x在存图中就是u到y的距离
dis[y]=dis[u]+x;
q.push({-dis[y],y});
}
}
}
}
void solve(){
for(int i=0;i<N;i++){
G[i].clear();
dis[i]=N;
vis[i]=0;
}
for(int i=1;i<=m;i++){
int u,v,len;
scanf("%lld %lld %lld", &u, &v, &len);
G[u].push_back({len,v});
}
int q,st;
scanf("%lld", &q);
while(q--){//多个起点
scanf("%lld",&st);
G[0].push_back({0,st});//超级源点到所有起点的距离=0
}
dij(0);
if(dis[s]==N) printf("-1\n");
else printf("%ld\n",dis[s]);
}
signed main()
{
while(~scanf("%d%d%d",&n,&m,&s)){
solve();
}
return 0;
}
浙公网安备 33010602011771号