洛谷 P3177 HAOI2015 树上染色

url: https://www.luogu.com.cn/problem/P3177

tag:
动态规划,树形DP

思路:
f[u][j] 表示以u为根节点的子树中,恰好有j个黑点时的收益。之后就是和分组背包类似的思路,对于每一个相连的节点,由当那个节点取k个黑点时更新过来,在不同的k值之间取一个最大值。使用 (k * (m - k) + (s[v] - k) * (n - m - s[v] + k)) * w[i] 来计算u和v之间边对答案的贡献。最后记得开long long。

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. const int N = 2020;
  7. int h[N], e[N * 2], ne[N * 2], w[N * 2], idx;
  8. long long n, m;
  9. long long s[N];
  10. long long f[N][N];
  11. void add(int a, int b, int c)
  12. {
  13. e[idx] = b;
  14. w[idx] = c;
  15. ne[idx] = h[a];
  16. h[a] = idx ++;
  17. }
  18. void dfs(int u, int fa)
  19. {
  20. s[u] = 1;f[u][0] = f[u][1] = 0;
  21. for (int i = h[u]; ~i; i = ne[i])
  22. {
  23. int v = e[i];
  24. if (v == fa) continue;
  25. dfs(v, u);
  26. s[u] += s[v];
  27. for (int j = min(s[u], m); j >= 0; j --)
  28. for (int k = 0; k <= min((long long)j, s[v]); k ++)
  29. if (f[u][j - k] != -1)
  30. {
  31. long long val = (k * (m - k) + (s[v] - k) * (n - m - s[v] + k)) * w[i];
  32. f[u][j] = max(f[u][j], f[u][j - k] + f[v][k] + val);
  33. }
  34. }
  35. }
  36. int main()
  37. {
  38. memset(h, -1, sizeof h);
  39. memset(f, -1, sizeof f);
  40. cin >> n >> m;
  41. for (int i = 0; i < n - 1; i ++)
  42. {
  43. int a, b, c;
  44. cin >> a >> b >> c;
  45. add(a, b, c), add(b, a, c);
  46. }
  47. dfs(1, 0);
  48. cout << f[1][m] << endl;
  49. return 0;
  50. }
添加新评论