[题解]P9751 [CSP-J 2023] 旅游巴士
思路
定义 \(d_{i,j}\) 表示从 \(1\) 走到 \(i\),并且满足 \(t \bmod k = j\) 的最小的符合题意的 \(t\)。
然后就可以直接跑一遍 Dijkstra 即可。
当要计算一条 \(u \to v\) 的边 \(w\) 时,如果当前时间不够无法达到 \(w\),那么需要将时间提到第一个时间大于 \(w\),并且模 \(k\) 相同的 \(x\) 即可。
code
#include <bits/stdc++.h>
#define fst first
#define snd second
#define re register
using namespace std;
typedef pair<int,int> pii;
const int N = 1e4 + 10,M = 2e4 + 10,K = 110,inf = 0x3f3f3f3f;
int n,m,k;
int d[N][K];
int idx,h[N],ne[M],e[M],w[M];
bool vis[N][K];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
inline void add(int a,int b,int c){
ne[idx] = h[a];
e[idx] = b;
w[idx] = c;
h[a] = idx++;
}
inline int up(int a,int b){
if (a % b == 0) return a / b;
return a / b + 1;
}
inline int get(int x,int y){
if (x >= y) return x;
return up(y - x,k) * k + x;
}
inline void dijkstra(int s){
priority_queue<pii,vector<pii>,greater<pii>> q;
d[s][0] = 0;
q.push({0,s});
while (!q.empty()){
pii t = q.top();
q.pop();
int dist = t.fst % k;
if (vis[t.snd][dist]) continue;
vis[t.snd][dist] = true;
for (re int i = h[t.snd];~i;i = ne[i]){
int j = e[i],lim = w[i];
int ndist = (dist + 1) % k,ntim = get(t.fst,lim) + 1;
if (d[j][ndist] > ntim){
d[j][ndist] = ntim;
q.push({d[j][ndist],j});
}
}
}
}
int main(){
memset(h,-1,sizeof(h));
memset(d,inf,sizeof(d));
n = read();
m = read();
k = read();
for (re int i = 1;i <= m;i++){
int a,b,c;
a = read();
b = read();
c = read();
add(a,b,c);
}
dijkstra(1);
if (d[n][0] >= inf) puts("-1");
else printf("%d",d[n][0]);
return 0;
}