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;
}

posted @ 2026-08-30 10:04  Denia-kawaii  阅读(3)  评论(0)    收藏  举报