POJ 1947 Rebuilding Roads 树形DP

题意:给你一颗树,问最少要去掉多少边才能得到一颗节点数为p的树


把节点1当做根节点,对于每一个节点,dp[u][i]表示节点u保留i个点最少去边数,我是把子树一颗颗地加进去,所以初始的dp[u][1] = 0,以前我也做过,不过是令dp[u][1] = 节点儿子数+1,根节点的话 = 儿子数,因为根节点不需要去父亲的边了,这应该是通常的做法吧。


#include <stdio.h>
#include <string.h>
#define INF 11111111

struct EDGE {
	int to, next;
}edge[888];

int E, head[222], cnt[222], cur[222], dp[222][222], ans, p;
void newedge(int u, int to) {
	edge[E].to = to;
	edge[E].next = head[u];
	head[u] = E++;
}

int min(int a, int b) {
	return a > b ? b : a;
}

void dfs(int u, int pre) {
	int i, j, k;
	dp[u][1] = 0;
	cnt[u] = 1;
	for(i = head[u];i != -1;i = edge[i].next) {
		int to = edge[i].to;
		if(to == pre)	continue;
		dfs(to, u);
		cnt[u] += cnt[to];
		for(j = 1;j <= cnt[u]; j++)
			cur[j] = INF;
		for(j = cnt[u]; j > 0;j --) {
			for(k = 1;k <= cnt[to]; k++)	if(j+k <= cnt[u] && dp[u][j] + dp[to][k] < cur[j+k])
				cur[j+k] = dp[u][j]+dp[to][k];
		}
		for(j = 1;j <= cnt[u]; j++)	{
			if(cur[j] < dp[u][j]+1)	dp[u][j] = cur[j];
			else	dp[u][j]++;
		}

	}
	if(pre != -1)
		ans = min(ans, dp[u][p]+1);
	else
		ans = min(ans, dp[u][p]);
}

void init() {
	memset(head, -1, sizeof(head));
	E = 0;
	ans = INF;
}

int main() {
	init();
	int n, i, a, b, j;
	scanf("%d%d", &n, &p);
	for(i = 0;i < n-1; i++) {
		scanf("%d%d", &a, &b);
		newedge(a, b);
		newedge(b, a);
	}
	for(i = 0;i <= n; i++)
		for(j = 0;j <= n; j++)
			dp[i][j] = INF;
	dfs(1, -1);
	printf("%d\n", ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值