AT_abc422_f [ABC422F] Eat and Ride 题解

题目传送门

思路

抽象 DP 好题,学到了很多。设 \(dp_{u,i}\) 代表到第 \(u\) 个点还能走 \(i\) 步的最小花费。

我们发现,对于每一条路径 \(u \to v\)\(dp_{v,i-1}\) 可以从 \(dp_{u,i}\) 更新。很显然,我们到了 \(w_v\),总重量就会增加 \(w_v\),且对于剩下的 \(i - 1\) 步,\(w_v\) 都会对答案有贡献。所以可以推出状态转移方程:

\[dp_{v,i-1} = \min\{dp_{v,i-1}, dp_{u,i} + w_v\times (i-1)\} \]

其中 \(u \to v\) 有路径。时间复杂度 \(\mathcal{O}(m^2)\),可以通过此题。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 5005;

int n, m;
int w[N], dp[N][N];
vector<int> tr[N];

signed main()
{
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%lld", &w[i]);
	for (int i = 1, u, v; i <= m; i++)
	{
		scanf("%lld%lld", &u, &v);
		tr[u].push_back(v);
		tr[v].push_back(u);
	}
	memset(dp, 0x3f, sizeof(dp));
	for (int i = 0; i <= m; i++)
		dp[1][i] = w[1] * i;
	for (int i = m; i >= 0; i--)
		for (int j = 1; j <= n; j++)
			for (int k : tr[j])
				dp[k][i - 1] = min(dp[k][i - 1], dp[j][i] + w[k] * (i - 1));
	for (int i = 1; i <= n; i++)
		printf("%lld\n", dp[i][0]);
	return 0;
}

posted @ 2026-01-04 16:48  lucasincyber  阅读(0)  评论(0)    收藏  举报