abc271_e Subsequence Path 题解

发布时间 2023-05-22 23:35:28作者: luogu_wsy0704

Subsequence Path

题意

\(n\) 个城市和 \(m\) 条有向道路,编号从 \(1\) 开始,第 \(i\) 条道路从 \(a_i\)\(b_i\),长度为 \(c_i\)

给定一个长度为 \(k\) 的序列 \(e\),我们定义从 \(1\)\(n\) 的一条路径是优秀的当且仅当:

  • 经过的边的编号按顺序构成 \(e\) 的一个子序列。

求从 \(1\)\(n\) 的优秀路径长度最小值,如果不存在,输出 -1

数据范围

  • \(2 \leqslant n \leqslant 2 \times 10^5\)\(1 \leqslant m, k \leqslant 2 \times 10^5\)
  • \(1 \leqslant a_i, b_i \leqslant n,\ a_i \ne b_i\ (1 \leqslant i \leqslant m)\)
  • \(1 \leqslant c_i \leqslant 10^9\ (1 \leqslant i \leqslant m)\)
  • \(1 \leqslant e_i \leqslant m\ (1 \leqslant i \leqslant k)\)

思路

看起来是一道图论题,但实际上是动态规划!

因为题目要求是 \(e\) 序列的一个子序列,那就可以变成一个类子序列 dp

  • 状态:\(dp_i\) 表示走到城市 \(i\) 的最短距离。
  • 转移:对于 \(1 \leqslant i \leqslant k\)\(dp_{b_{e_i}} = \min({dp_{a_{e_i}} + c_{e_i}, dp_{b_{e_i}}})\)
  • 初始状态:\(dp_1=0\)
  • 目标状态:\(dp_n\)

不开 long long 见祖宗!

复杂度

  • 时间:\(O(n+m+k)\)
  • 空间:\(O(n+m)\)

Code

点击查看代码
#include <iostream>

using namespace std;
using ll = long long; // 前排提示:不开 long long 见祖宗!

const int N = 2e5 + 10;

int n, m, k, e, a[N], b[N], c[N];
ll dp[N];

int main () {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m >> k;
  for (int i = 2; i <= n; i++) {
    dp[i] = 1e18; // 赋值最大值
  }
  for (int i = 1; i <= m; i++) {
    cin >> a[i] >> b[i] >> c[i]; // 记录每条边
  }
  for (int i = 1; i <= k; i++) {
    cin >> e;
    dp[b[e]] = min(dp[b[e]], dp[a[e]] + c[e]); // 转移
  }
  cout << (dp[n] < 1e18 ? dp[n] : -1);
  return 0;
}