[河南萌新联赛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");
}
posted @ 2025-08-06 20:32  orzzzzz  阅读(37)  评论(4)    收藏  举报