YBT1715 公交旅行
在这个城市中有 \(n\) 个站台和 \(m\) 条公交线路,第i条公交线路由 \(t_i\) 个站台组成,记为 \(s_i\),1,\(s_i\),2,…,\(s_i\),\(t_i\)。在 0 时刻,第 \(i\) 辆公交车会处在 \(s_i\),1 站台,之后每个时刻公交都会到达路线中的下一个站台。当公交车到达终点站后,它下一个时刻将会回到出发的站台,注意一个站台可能在一条线路中出现多次,但不会相邻。
可以用一种很经典的思路,将公交车和站台都看作点,对于边权额外处理即可:
- 如果出发点为站台(终点为车),则边权为等待时间(以到达 \(u\) 点的最小时间为初始时间),利用取模处理。
- 如果出发点为车(终点为站台),则边权为距离,做法与上类似。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5;
const int inf = 0x3f3f3f3f;
struct node {
int u; int dis;
bool operator < (const node &x) const {
return dis > x.dis;
}
};
int n,m;
vector<int> tim[maxn + 5]; // 站台i的车z2c[i]
vector<int> bus[maxn + 5]; // 车i经过的站台c2z[i]
vector<int> id[maxn + 5];
priority_queue<node> q;
int dis[maxn * 2 + 5];
int vis[maxn * 2 + 5];
int main() {
cin >> n >> m;
for (int i = 1;i <= m;i ++) {
int t; cin >> t;
for (int j = 0;j < t;j ++) {
int x; cin >> x;
bus[i].push_back(x);
tim[x].push_back(j);
id[x].push_back(i);
}
}
memset(dis,inf,sizeof(dis));
for (int i = 0;i <= n + m;i ++) dis[i] = inf,vis[i] = 0;
dis[1] = 0,q.push((node){1,dis[1]});
while (!q.empty()) {
int u = q.top().u; q.pop();
if (vis[u]) continue;
vis[u] = 1;
if (u <= n) { // u 是站台
int len = tim[u].size();
for (int i = 0;i < len;i ++) { // 枚举车
int v = id[u][i] + n,l = bus[v - n].size();
int now = dis[u] % l; // 车的位置car,站台u位置p
int d = 0ll;
if (tim[u][i] >= now) d = tim[u][i] - now;
else d = tim[u][i] + l - now;
if (dis[v] > d + dis[u]) {
dis[v] = d + dis[u];
q.push((node){v,dis[v]});
}
}
} else { // u 是车
int len = bus[u - n].size(),t = dis[u] % len; // t: 车的位置
for (int i = 0;i < len;i ++) { // 枚举站台
int v = bus[u - n][t];
if (dis[v] > dis[u] + i) {
dis[v] = dis[u] + i;
q.push((node){v,dis[v]});
}
t = (t + 1) % len;
}
}
}
for (int i = 2;i <= n;i ++) cout << (dis[i] == inf ? -1 : dis[i]) << " ";
return 0;
}

浙公网安备 33010602011771号