• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
P9751 [CSP-J 2023] 旅游巴士 (Dijkstra + 分层图DP)

思路

直接建分层图即可,每个点的状态都可以表示模 \(k\) 意义下的时间,因此每个点可以拆成 \(k\) 个, 然后我们在跑Dijkstar就行了

Code

#include <bits/stdc++.h>
#define r(x, y) ((x) * (n + 1) + (y))
#define ss second
#define ff first
using i64 = long long;

typedef std::pair<int, int> PII;

const int N = 4e6 + 10;

int n, m, k, f[N];

bool st[N];

std::vector<std::pair<int, int>> G[N];

/*
	设到到达s的最小时间为x

	则有 x + 0, x + 1, x + 2, ... , x + k - 1 情况

	我们设f[i][s] 表示第i种到达s的最小花费时间

	考虑如何转移:
	考虑存在边 u->s, s的点权重为a

	若f[i][s] + 1 < a, 那么我们需要等待 f[i] + 1 + nk >= a 时间, 取最小的n

	若f[i][s] + 1 > a
*/

void dijkstra() {
	std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>> h1;

	memset(f, 0x3f, sizeof f);

	// 先传入 0s 进入 第1个点
	f[r(0, 1)] = 0;

	h1.push({0, r(0, 1)});

	while (h1.size()) {
		auto t = h1.top(); h1.pop();

		i64 u = t.ss % (n + 1);

		// std::cout << u << "\n";

		if (st[t.ss]) continue;

		st[t.ss] = true;

		for (auto x: G[u]) {
			i64 tim = f[t.ss] + 1;

			// std::cout << x.ff << "\n";

			// 如果到达时, 该边还未开放	
			if (x.ss > t.ff) {
				// 向上取整
				tim += (x.ss - f[t.ss] + (k - 1)) / k * k;
			}


			if (f[r(tim % k, x.ff)] > tim) {
				f[r(tim % k, x.ff)] = tim;

				h1.push({tim, r(tim % k, x.ff)});
			}
		}
	}

}

int main() {
	std::cin >> n >> m >> k;

	while (m --) {
		int u, v, a; std::cin >> u >> v >> a;

		G[u].push_back({v, a});
	}

	// if (n == 1) {
	// 	std::
	// }
	
	dijkstra();


	if (f[r(0, n)] == 0x3f3f3f3f) {
		return puts("-1"), 0;
	}

	std::cout << f[r(0, n)];
}
posted on 2023-10-29 12:08  Jack404  阅读(203)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3