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 */