diff --git a/TangDou/CSP-J/J-2023/bus.cpp b/TangDou/CSP-J/J-2023/bus.cpp index 87ec493..1a5a1bb 100644 --- a/TangDou/CSP-J/J-2023/bus.cpp +++ b/TangDou/CSP-J/J-2023/bus.cpp @@ -1,7 +1,7 @@ #include using namespace std; const int N = 10010, M = N << 1, K = 110; // 节点个数上限,边数上限,发车间隔时长上限 -const int INF = 0x3f3f3f3f; // Dijsktra专用正无穷 +const int INF = 0x3f3f3f3f; struct Node { int u, r, d; // u节点编号,r状态,d最短到达时间 @@ -22,14 +22,14 @@ dis[u][i]表示到达第u处地点,并且到达时间mod k = i的情况下的 */ int dis[N][K], st[N][K]; int main() { - memset(h, -1, sizeof h); + memset(h, -1, sizeof h); // 初始化链式前向星 int n, m, k; cin >> n >> m >> k; - for (int i = 0; i < m; i++) { + while (m--) { int a, b, c; cin >> a >> b >> c; - add(a, b, c); // 从a到b建一条边,c权值为开放时间 + add(a, b, c); // 从a到b建一条边,c为此路径的开放时间 } // 初始状态,1号点在状态0时最短距离为0,其它点的最短距离为无穷大 @@ -49,14 +49,15 @@ int main() { int r = q.top().r; // 节点状态r q.pop(); - if (st[u][r]) continue; // 该状态已经加入到集合中,也就是已经被搜索过 + if (st[u][r]) continue; + // 该状态已经加入到集合中,也就是已经被搜索过 // 先被搜索过在队列宽搜中意味着已经取得了最短路径 st[u][r] = 1; for (int i = h[u]; ~i; i = ne[i]) { // 枚举邻接点v和连接到v节点道路的开放时间 int v = e[i]; // v节点,也就是下一个节点 int t = w[i]; // v节点的开放时间 - int d = dis[u][r]; // 到达(u,p)这个状态时的最短距离d + int d = dis[u][r]; // 到达(u,r)这个状态时的最短距离d int j = (r + 1) % k; // v节点的状态应该是u节点的状态+1后再模k // 如果到达时间小于开放时间,则将到达时间向后延长若干个k的整数倍(向上取整) diff --git a/TangDou/CSP-J/J-2023/bus.md b/TangDou/CSP-J/J-2023/bus.md index d089784..12337f7 100644 --- a/TangDou/CSP-J/J-2023/bus.md +++ b/TangDou/CSP-J/J-2023/bus.md @@ -166,87 +166,3 @@ int main() { } ``` - -### 办法二:二分+宽搜 - -![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202311071051699.png) - -疑问与解答: -#### $Q$:为什么要建反图? -答:举个栗子,比如从$1$出发有如下路径 - - -```cpp {.line-numbers} -#include -using namespace std; -const int N = 10010, M = N << 1, K = 110; - -// 链式前向星 -int e[M], h[N], idx, w[M], ne[M]; -void add(int a, int b, int c = 0) { - e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; -} - -// 入队列的结构体 -struct Node { - int id; // 节点号 - int r; // %k的余数 -}; - -int dis[N][K]; // 最短路径 -int n, m, k; // n个节点,m条边,时间是k的整数倍,即 %k=0 - -bool bfs(int mid) { - memset(dis, -1, sizeof dis); - queue q; - dis[n][0] = mid * k; - q.push({n, 0}); - - while (q.size()) { - int u = q.front().id; - int r = q.front().r; - q.pop(); - - if (dis[u][r] == 0) continue; // 反着走,距离为0,就不需要继续走了,剪枝 - - for (int i = h[u]; ~i; i = ne[i]) { - int v = e[i]; // 前序节点 - int p = (r - 1 + k) % k; // 前序节点合法状态 - if (~dis[v][p]) continue; // 如果前序点的合法状态不等于-1,表示已经被宽搜走过了,根据宽搜的理论,就是已经取得了最短距离,不需要再走 - if (dis[u][r] - 1 < w[i]) continue; // 现在的最短距离是dis[u][r],那么前序的距离应该是dis[u][r]-1,那么,如果dis[u][r]-1> n >> m >> k; - - while (m--) { - int a, b, c; - cin >> a >> b >> c; - add(b, a, c); - } - - int l = 0, r = (1e6 + 1e4) / k, ans = -1; - while (l < r) { - int mid = l + r >> 1; - if (bfs(mid)) { - ans = mid * k; - r = mid; - } else - l = mid + 1; - } - cout << ans << endl; - return 0; -} -```