https://ac.nowcoder.com/acm/contest/5389/D
我也不敢说我学会了,说说总结的经验吧。
当假设dp[a][b],dp内部状态是小于等于b的时候,不必枚举b,只要让b尽可能大然后取dp[a][b] = min(dp[a][b-1],dp[a][b])就行了
应该就是这样了,代码方下来,以后多看几天
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
const int maxn = 5050 + 11;
typedef long long ll;
vector<int>G[maxn];
void add(int be, int en) {
G[be].push_back(en);
}
ll dp[maxn][maxn];
int list[maxn];
int k;
int dfs(int x, int fa) {
dp[x][0] = list[x];
for (int s = 0; s < G[x].size(); s++) {
int p = G[x][s];
if (p == fa) continue;
dfs(p, x);
dp[x][0] += dp[p][k - 1];
}
for (int i = 1; i < k; i++) {
ll tp = 0;
for (int j = 0; j < G[x].size(); j++) {
int p = G[x][j];
if (p == fa) continue;
dp[x][i] = min(dp[x][i] + dp[p][min(i - 1, k - i - 1)], dp[p][i - 1] + tp);
tp += dp[p][min(i - 1, k - i - 1)];
}
dp[x][i] = min(dp[x][i], dp[x][i - 1]);
}
return 0;
}
int main() {
int n;
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &list[i]);
}
for (int i = 1; i < n; i++) {
int be, en;
scanf("%d %d", &be, &en);
add(be, en);
add(en, be);
}
dfs(1, -1);
cout << dp[1][k - 1] << endl;
return 0;
}
/*
6 3
1 2 3 4 5 6
1 2
2 5
3 5
5 6
6 4
输出5
*/