思路
由于题面中要求最后的便签是 p p p 的倍数,这是一个非常经典的分层图题。
将每个点拆分成 p p p 个点。为了方便,我们设点 ( i , j ) (i,j) (i,j) 表示原图中点 i i i 的第 j j j 层,即到点 i i i 时剩下便签数对 p p p 取模为 j j j。
考虑建图。对于原图中的每一条边 ( u , v , w ) (u,v,w) (u,v,w),在分层图上建边时,枚举 u u u 的层数 j j j,那么到了 v v v 的时候层数就变成了 ( j + w ) m o d p (j+w)\bmod p (j+w)modp。所以连接一条从 ( u , j ) (u,j) (u,j) 到 ( v , ( j + w ) m o d p ) (v,(j+w)\bmod p) (v,(j+w)modp),权值为 w w w 的边。
问题就被转化成了求 ( s , 0 ) (s,0) (s,0) 到 ( t , 0 ) (t,0) (t,0) 的最短路。跑一遍 Dijkstra 即可。
实测堆优化开 O2 才能过。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<typename T> inline void read(T &x)
{
x = 0;
T f = 1;char ch = getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
{
f = -1,ch = getchar();
break;
}
ch = getchar();
}
while(ch>='0'&&ch<='9')
x = (x<<3)+(x<<1)+ch-48,ch = getchar();
x*=f;
}
template<typename T> inline T read()
{
T x;read(x);return x;
}
template<typename T> void write(T x)
{
if(x<0) x = -x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+48);
}
template<typename T> inline void writen(T x)
{
write(x);
putchar(10);
}
const int N = 5e4+5,M = 2e5+5;
int n,m,p,s,t,cnt,head[N*50],to[M*50],nxt[M*50];
ll g[M*50];
inline void add(int x,int y,int z)
{
nxt[++cnt] = head[x];
head[x] = cnt;
to[cnt] = y,g[cnt] = z;
}
inline int id(int x,int y){return (x-1)*p+y+1;}//(i,j) 的编号
inline int get(int x){return (x-1)/p+1;}//(i,j) 编号对应的 i
ll dis[N*50];
int pre[N*50];
bool vis[N*50];
void print(int x)//递归输出路径
{
if(pre[x]) print(pre[x]),putchar('-'),putchar('>');
write(get(x));
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m),read(p),read(s),read(t);
for(int i = 1,u,v,w;i<=m;i++)
{
read(u),read(v),read(w);
for(int j = 0;j<p;j++)
add(id(u,j),id(v,(j+w)%p),w);
}
priority_queue<pair<ll,int> > q;
q.push({0,id(s,0)});
for(int i = 1;i<=n*p;i++) dis[i] = 2e18;
dis[id(s,0)] = 0;
while(!q.empty())//Dijkstra
{
int u = q.top().second;q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u];i;i = nxt[i])
{
int v = to[i];
if(dis[v]>dis[u]+g[i])
dis[v] = dis[u]+g[i],pre[v] = u,q.push({-dis[v],v});
}
}
if(dis[id(t,0)]==2e18) return puts("jjc fails in travelling"),0;//不连通
writen(dis[id(t,0)]);
print(id(t,0));
return 0;
}