HDU 5905 Black White Tree(树型DP)

题目链接  Black White Tree

树型DP,设$f[i][j]$为以$i$为根的子树中大小为$j$的连通块中可以包含的最小黑点数目。

$g[i][j]$为以$i$为根的子树中大小为$j$的连通块中可以包含的最大黑点数目。

$F[i]$为大小为$i$的连通块中可以包含的最小黑点数目

$G[i]$为大小为$j$的连通块中可以包含的最大黑点数目

做一遍树上DP即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int N = 2020;

int n;
char s[N];
int a[N];
int T;
vector <int> v[N];
LL ans = 0;
int F[N << 1], G[N << 1];
int f[N][N], g[N][N];
int sz[N];

void dfs(int x, int fa){
	sz[x] = 1;
	if (a[x]) f[x][1] = g[x][1] = 1;
	else f[x][1] = g[x][1] = 0;


	for (auto u : v[x]){
		if (u == fa) continue;
		dfs(u, x);
		dec(i, sz[x], 1){
			rep(j, 1, sz[u]){
				f[x][i + j] = min(f[x][i + j], f[x][i] + f[u][j]);
				g[x][i + j] = max(g[x][i + j], g[x][i] + g[u][j]);
			}
		}

		sz[x] += sz[u];
	}

	rep(i, 1, sz[x]){
		F[i] = min(F[i], f[x][i]);
		G[i] = max(G[i], g[x][i]);
	}
}

inline int query(int x, int y){
	return (F[x + y] <= y && G[x + y] >= y) ? 1 : 0;
}	

int main(){

	scanf("%d", &T);
	while (T--){
		scanf("%d", &n);
		scanf("%s", s + 1);
		rep(i, 1, n) a[i] = (int)s[i] - 48;

		rep(i, 0, n) v[i].clear();

		rep(i, 0, n) rep(j, 0, n){
			f[i][j] = 1 << 27;
			g[i][j] = 0;
		}

		rep(i, 0, n << 1) F[i] = 1 << 27, G[i] = 0;

		rep(i, 1, n - 1){
			int x, y;
			scanf("%d%d", &x, &y);
			v[x].push_back(y);
			v[y].push_back(x);
		}
		
		ans = 0;
		dfs(1, 0);
		rep(i, 0, n) rep(j, 0, n) ans += (LL)(i + 1) * (j + 1) * query(i, j);
		printf("%lld
", ans + 1);
	}



	return 0;
}
原文地址:https://www.cnblogs.com/cxhscst2/p/7599010.html