ABC271E解题报告
题意
给你 \(n\) 个点,\(m\) 条路从 \(a_i\) 到 \(b_i\) 长度为 \(c_i\),一段长为 \(k\) 的序列 \(e\)。求从 \(1\) 号点到 \(n\) 号点最短的好路长度。
对于好路,如果经过的边序号(输入时的顺序)是 \(e\) 的子序列,那么称作一条好路。
分析
看起来是一道图论,但是发现题目说子序列,可以想到用 dp 去求。
状态表示:子序列我们可以选或不选,对应到上面的边就是加不加这条边的权值。这样一来我们就不需要去记录边而是记录到这一点权值的最小值。综上,\(dp_i\) 表示到第 \(i\) 个点好路的权值最小值。
状态计算:根据状态表示的思想,子序列上 dp 我们不需要考虑前面选了哪几条边,我们只关心这个点经过这次操作后权值的最小,所以得到方程 \(dp_{b_i}=\min(dp_{b_i},dp_{a_i}+c_i)\)。
basecase:显然一号点最小权值为 \(0\),\(dp_1=0\)。
ans:最终只要判断 \(dp_n\) 是否能到达(是否为极大值),能则输出 \(dp_n\),否则输出 \(-1\)。
不开 long long
见祖宗?
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, k;
int a[200005], b[200005], c[200005], e[200005], dp[200005];
signed main(){
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) cin >> a[i] >> b[i] >> c[i];
for (int i = 1; i <= k; i++) cin >> e[i];
memset(dp, 0x3f, sizeof(dp));
dp[1] = 0;
for (int i = 1; i <= k; i++){
dp[b[e[i]]] = min(dp[b[e[i]]], dp[a[e[i]]] + c[e[i]]);
}
if (dp[n] == 0x3f3f3f3f3f3f3f3f) cout << "-1";
else cout << dp[n];
return 0;
}