[GXOI/GZOI2019]旅行者

Luogu5304

给定一个单向图和一些关键点,求所有关键点对中最短的单向距离

以所有点为起点,正反两边跑(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
",ans);
}

int main(){
//	freopen("1.in","r",stdin);
//	freopen("city.out","w",stdout);
    for(int i=read();i;i--) solve();
}
原文地址:https://www.cnblogs.com/lizehon/p/10827513.html