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;
}

浙公网安备 33010602011771号