window.cnblogsConfig = {//可以放多张照片,应该是在每一个博文上面的图片,如果是多张的话,那么就随机换的。 homeTopImg: [ "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png", "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png" ], }

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;
}
posted @ 2024-01-18 07:48  CCF_IOI  阅读(19)  评论(0)    收藏  举报