[HAOI 2015] 树上染色(树上背包) | 错题本

文章目录

  • 题目
  • 分析
  • 代码

题目

[HAOI 2015] 树上染色(树上背包)

分析

考虑 d p [ u ] [ i ] dp[u][i] dp[u][i] 表示 u u u 子树中有 i i i 个黑点时,对答案的贡献,转移过程中计算边 ( u , v ) (u, v) (u,v) 的贡献即可。注意贡献有白色贡献和黑色贡献。

代码

#include 
#include 
#include 

typedef long long LL;

const int MAXN = 2000;

int N, K;

struct Node {
	int v, w, nxt;
}E[MAXN * 2 + 5];
int EdgeCnt;
int Adj[MAXN + 5];

void AddEdge(int u, int v, int w) {
	E[++EdgeCnt] = (Node){v, w, Adj[u]};
	Adj[u] = EdgeCnt;
}

int Size[MAXN + 5];
LL Dp[MAXN + 5][MAXN + 5];

void Dfs(int u, int fa) {
	Size[u] = 1;
	for (int i = Adj[u]; i; i = E[i].nxt) {
		int v = E[i].v;
		if (v != fa)
			Dfs(v, u), Size[u] += Size[v];
	}
	Dp[u][0] = Dp[u][1] = 0;
	for (int i = Adj[u]; i; i = E[i].nxt) {
		int v = E[i].v; LL w = E[i].w;
		if (v != fa) {
			for (int j = std::min(K, Size[u]); j >= 0; j--) {
				int lim = std::min(Size[v], j);
				for (int k = 0; k <= lim; k++) {
					if (~Dp[u][j - k]) {
						LL p = Size[v] - k;
						LL delta = w * (k * (K - k) + p * (N - K - p));
						Dp[u][j] = std::max(Dp[u][j], Dp[u][j - k] + Dp[v][k] + delta);
					}
				}
			}
		}
	}
}

int main() {
	scanf("%d%d", &N, &K);
	for (int i = 1; i < N; i++) {
		int u, v, w; scanf("%d%d%d", &u, &v, &w);
		AddEdge(u, v, w), AddEdge(v, u, w);
	}
	memset(Dp, -1, sizeof Dp);
	Dfs(1, 0);
	printf("%lld\n", Dp[1][K]);
	return 0;
}

你可能感兴趣的:([,错题本,],#,树形,DP,动态规划,背包问题)