[河南萌新联赛2025第(四)场]H (DP 图论)
题意分析
图是一个 分层有向无环图(DAG),并且每条边满足:
\[d_v = d_u + 1
\]
即每次只能从当前层走到下一层。
每个节点有 进入条件 \(a_i\) 和 收益 \(b_i\):
- 若当前战力 \(k < a_i\),则无法进入该节点;
- 若 \(k \ge a_i\),则进入后战力变为 \(k + b_i\)。
机器人最多可以使用 3 次传送,即可以从当前层传送到下一层的任意节点。
问题:
是否能从 \(1\) 号节点到达 \(n\) 号节点?
👇👇👇
题目链接
1. 层次划分
- 通过BFS计算每个节点的层次(距离):
- 层次
d[i]表示从节点1到节点i的最短步数 - 形成从层0到层
d[n]的严格分层结构 - eg:seg[i]表示从1节点移动i步可以到的点数集合 (也可视为一层)
- 层次
2. DP状态定义
设dp[u][t]表示:
- 到达节点u时使用t次传送能达到的最大战力值
- 不可达状态设为负无穷
初始条件:
- 若
k ≥ a[1],则dp[1][0] = k + b[1]否则到不了第一个节点 直接输出NO
3. 状态转移
1:普通移动(\(i-1\) 层 → \(i\) 层)
对于当前层节点 \(u\) 和下一层节点 \(v\):
\[\text{如果可行} \ \ 即: dp[u][t] \ge a[v]\ ,\
\text{那么就可直接从上一层转移}:
\]
\[则有:dp[v][t] = \max \bigl(dp[v][t],\ dp[u][t] + b[v]\bigr)
\]
2:传送(\(i-1\) 层 → \(i\) 层):
-
传送过程说明:
在\(i-1\)层 中,先统计出每个传送次数 \(t\) 下的全局最大战力 \(p[t]\)。
对于下一层所有节点 \(v\):
-
若 \(p[t] >=a[v]\) 说明当前\(i-1\)层传送\(t\)次的最大战力可以到下一个节点\(v\),则有:
\[dp[v][t+1] = \max\bigl(dp[v][t+1],\ p[t] + b[v]\bigr) \]
由于传送最多 3 次,所以 \(t\) 的范围是 \(0 \sim 3\)。
-
最终判断
若存在某个 \(t\) 使得 \(dp[n][t] > -\infty\),则说明能到达终点,输出 "YES",否则输出 "NO"。
void solve() {
int n, m, k;
cin >> n >> m >> k;
vi<i64> a(n + 1), b(n + 1);
rep1(i, n) cin >> a[i] >> b[i];
vvi<int> G(n + 1);
rep0(i, m) {
int u, v;
cin >> u >> v;
G[u].pb(v);
}
vi<int> d(n + 1, -1);
queue<int> q;
d[1] = 0;
q.push(1);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : G[u]) {
if (d[v] == -1) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
if (d[n] < 0) {
cout << "NO\n";
return;
}
vvi<int> seg(d[n] + 1);
rep1(i, n) {
if (d[i] >= 0 && d[i] <= d[n]) seg[d[i]].pb(i);
}
vi<array<i64, 4>> dp(n + 1);
rep1(i, n) dp[i].fill(mininff);
if (a[1] > k) {
cout << "NO\n";
return;
}
dp[1][0] = k + b[1];
rep1(i, d[n]) {
for (auto u : seg[i - 1]) {
for (auto v : G[u])
if (d[v] == i) {
rep0(t, 4) {
if (dp[u][t] >= a[v]) dp[v][t] = max(dp[v][t], dp[u][t] + b[v]);
}
}
}
array<i64, 4> p;
p.fill(mininff);
for (auto u : seg[i - 1]) {
rep0(t, 4) p[t] = max(p[t], dp[u][t]);
}
for (auto v : seg[i]) {
rep0(t, 3) {
if (p[t] >= a[v]) dp[v][t + 1] = max(dp[v][t + 1], p[t] + b[v]);
}
}
}
bool ok = false;
rep0(t, 4) {
if (dp[n][t] > mininff) {
ok = true;
break;
}
}
cout << (ok ? "YES\n" : "NO\n");
}

浙公网安备 33010602011771号