Codeforces 581F Zublicanes and Mumocrates(树型DP)

题目链接  Round 322 Problem F

题意  给定一棵树,保证叶子结点个数为$2$(也就是度数为$1$的结点),现在要把所有的点染色(黑或白)

  要求一半叶子结点的颜色为白,一半叶子结点的颜色为黑,求边权和的最小值。

  若一条边连接的两个点颜色不一样,则该条边边权为$1$,否则为$0$。

 

考虑树型$DP$。

$f[x][i][j]$表示当以$x$为根的子树中有$i$个叶子结点染成黑色并且$x$的颜色为$j$的时候边权和的最小值。

这道题计算$size$的时候只考虑叶子结点,不考虑除叶子结点以外的结点。

$DP$的时候叶子结点和其他结点分开考虑,注意状态转移的时候要开个过渡数组$g$,否则在状态转移过程中出现的最小值可能会被错误地保存到最后。

时间复杂度$O(n^{2})$

 

#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)
#define MP		make_pair
#define fi		first
#define se		second


typedef long long LL;

const int N = 5e3 + 10;

int f[N][N][2], sz[N], in[N];
int n, all, root;
int g[N][2];
vector <int> v[N];

void up(int &a, int b){ a = min(a, b);}

void dfs(int x, int fa){
	if (in[x] == 1){
		sz[x] = 1;
		f[x][1][1] = 0;
		f[x][0][0] = 0;
		return;
	}
	f[x][0][0] = f[x][0][1] = 0;
	for (auto u : v[x]){
		if (u == fa) continue;
		dfs(u, x);
		memset(g, 0x3f3f3f3f, sizeof g);
		dec(i, sz[x], 0){
			dec(j, sz[u], 0){
				up(g[i + j][1], f[x][i][1] + f[u][j][1]);
				up(g[i + j][1], f[x][i][1] + f[u][j][0] + 1);
				up(g[i + j][0], f[x][i][0] + f[u][j][1] + 1);
				up(g[i + j][0], f[x][i][0] + f[u][j][0]);
			}
		}
		memcpy(f[x], g, sizeof f[x]);
		sz[x] += sz[u];
	}
}

int main(){

	scanf("%d", &n);
	rep(i, 2, n){
		int x, y;
		scanf("%d%d", &x, &y);
		v[x].push_back(y);
		v[y].push_back(x);
		++in[x];
		++in[y];
	}

	if (n == 2) return 0 * puts("1");
	rep(i, 1, n) if (in[i] == 1) ++all;
	else root = i;
	memset(f, 0x3f3f3f3f, sizeof f);
	dfs(root, 0);
	printf("%d\n", min(f[root][all / 2][0], f[root][all / 2][1]));
	return 0;
}

 

  

 

posted @ 2018-03-11 23:59  cxhscst2  阅读(188)  评论(0编辑  收藏  举报