题解 P5304 【[GXOI/GZOI2019]旅行者】
Dijkstra。
这道题目简直是弟弟级别的……
考虑每条边
同时,我们还要记录这个城市的编号,如果两个城市相同,那么相当于走了一个环回到其本身了,不能计入答案。
正反跑两边 Dijkstra,分别染色。染色也就是在跑 Dijkstra 的过程中记录离这个点最近的城市,具体可以见代码。
#include<bits/stdc++.h>
#define MAXN 100005
#define MAXM 500005
#define reg register
#define inl inline
#define ll long long
using namespace std;
int cnt,fst[MAXN],to[MAXM],nxt[MAXM],w[MAXM];
int n,m,k,col[2][MAXN],a[MAXN],fr[MAXM],tx[MAXM],ww[MAXM];
ll dis[2][MAXM];
struct Node
{
int u;
ll dis;
bool operator < (const Node &x) const
{
return x.dis<dis;
}
};
priority_queue <Node> q;
template <typename T> inl void Read(reg T &x)
{
x=0;
reg int fu=1;
reg char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') fu=-1;
for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch-48);
x*=fu;
}
inl void AddEdge(reg int u,reg int v,reg int c)
{
to[++cnt]=v;
nxt[cnt]=fst[u];
fst[u]=cnt;
w[cnt]=c;
}
inl void Dijkstra(reg int id)
{
memset(dis[id],60,sizeof(dis[id]));
memset(col[id],0,sizeof(col[id]));
for(reg int i=1;i<=k;i++)
{
dis[id][a[i]]=0;
col[id][a[i]]=a[i];
q.push((Node){a[i],0});
}
while(!q.empty())
{
reg Node now=q.top();
q.pop();
reg int u=now.u;
reg ll d=now.dis;
if(d!=dis[id][u]) continue;
for(reg int i=fst[u];i;i=nxt[i])
{
reg int v=to[i];
if(dis[id][v]>dis[id][u]+w[i])
{
dis[id][v]=dis[id][u]+w[i];
col[id][v]=col[id][u];
q.push((Node){v,dis[id][v]});
}
}
}
}
int main()
{
int Time;
Read(Time);
while(Time--)
{
cnt=0;
memset(fst,0,sizeof(fst));
Read(n);
Read(m);
Read(k);
for(reg int i=1;i<=m;i++)
{
int x,y,z;
Read(x);
Read(y);
Read(z);
fr[i]=x;
tx[i]=y;
ww[i]=z;
if(x^y) AddEdge(x,y,z);
}
for(reg int i=1;i<=k;i++) Read(a[i]);
Dijkstra(0);
cnt=0;
memset(fst,0,sizeof(fst));
for(reg int i=1;i<=m;i++) if(fr[i]^tx[i]) AddEdge(tx[i],fr[i],ww[i]);
Dijkstra(1);
reg ll ans=1e18;
for(reg int i=1;i<=m;i++)
{
reg int u=fr[i],v=tx[i],c=ww[i];
if(col[0][u] && col[1][v] && col[0][u]!=col[1][v]) ans=min(ans,dis[0][u]+dis[1][v]+c);
}
printf("%lld\n",ans);
}
return 0;
}