给定一个单向图和一些关键点,求所有关键点对中最短的单向距离
以所有点为起点,正反两边跑\(dijkstra\),用每一条边来更新答案。
注意两个端点不能由同一个关键点更新得来。
多组数据记得把图清空!
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
//#define int long long
using namespace std;
typedef long long LL;
typedef pair<LL,int> pli;
const LL INF=1e18+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
}
const int N=1e5+5;
const int M=5e5+5;
struct Edge{
int v,w,nxt;
}e[M];
int first[N],Ecnt=0;
inline void Add_edge(int u,int v,int w=0){
e[++Ecnt]=(Edge){v,w,first[u]};
first[u]=Ecnt;
}
LL dis[2][N];int col[2][N];
int x[M],y[M],w[M],city[N];
bool vis[N];
int n,m,K;LL ans;
inline void dijkstra(LL *dis,int *col){
priority_queue <pli,vector<pli>,greater<pli> > q;
for(int i=1;i<=n;i++) dis[i]=INF,vis[i]=false;//基本操作
for(int i=1;i<=K;i++) dis[city[i]]=0,col[city[i]]=city[i],q.push(pli(0,city[i]));
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(dis[u]+w<dis[v]){
dis[v]=dis[u]+w;
col[v]=col[u];
q.push(pli(dis[v],v));
}
}
}
}
inline void solve(){
n=read(),m=read(),K=read();
ans=INF;
for(int i=1;i<=n;i++) first[i]=0;
Ecnt=0;
for(int i=1;i<=m;i++){
x[i]=read(),y[i]=read(),w[i]=read();
if(x[i]!=y[i]) Add_edge(x[i],y[i],w[i]);
}
for(int i=1;i<=K;i++) city[i]=read();
dijkstra(dis[0],col[0]);
for(int i=1;i<=n;i++) first[i]=0;
Ecnt=0;///
for(int i=1;i<=m;i++){
if(x[i]!=y[i]) Add_edge(y[i],x[i],w[i]);//反向建边
}
dijkstra(dis[1],col[1]);
for(int i=1;i<=m;i++){
if(col[0][x[i]]&&col[1][y[i]]&&col[0][x[i]]!=col[1][y[i]])//必须要是关键点
ans=min(ans,dis[0][x[i]]+dis[1][y[i]]+w[i]);
}
printf("%lld\n",ans);
}
int main(){
// freopen("1.in","r",stdin);
// freopen("city.out","w",stdout);
for(int i=read();i;i--) solve();
}