【DP】poj1947

28 篇文章 0 订阅

题目大意:给出一棵树,让你隔断一些边,使得割完后剩下的联通块里有某个联通块刚好包含k个节点,然后隔断的边尽量少

也是一道典型的树形dp

然后很明显能看出要以每个节点i及其子树中保留j个节点最少割多少次来作为状态

这个题大概难点在初始化吧。。想了好久。。。

我当时的初始化是f[i][1]=vec[i].size()-1,也就是i节点的总儿子数

然后转移分两种

一种是选了某个儿子那就是now=min(now,f[u][j-k]+f[tmp][k]-1);因为我一开始初始化的时候是默认都断开的,所以我现在必须把多删的这一条边减去

第二种就是不选某个儿子f[u][j]=min(now,f[u][j]);

写滚动数组不知道会不会超时反正拿个now来更新不会有问题。。。

最后答案要统计每一个节点的f[i][k]。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm> 
#include<vector>
using namespace std;
int f[210][210],n,p;
int ans=2000000000;
vector <int> vec[210]; 
void dfs(int u,int v)
{		
	f[u][1]=vec[u].size()-1;
	if (v==0) f[u][1]++;
	for (int i=vec[u].size()-1;i>=0;i--)
	{
		int tmp=vec[u][i];
		if (tmp==v) continue;
		dfs(tmp,u);
		for (int j=p;j;j--)
		{
			int now=f[u][j];
			for (int k=1;k<=j-1;k++)
				now=min(now,f[u][j-k]+f[tmp][k]-1);
			f[u][j]=min(now,f[u][j]);
		}	
	} 
	if (v!=0) ans=min(ans,f[u][p]+1);
	else ans=min(ans,f[u][p]);
}
int main()
{
	int x,y;
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout); 
	scanf("%d%d",&n,&p);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			f[i][j]=1000000000;
	for (int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		vec[x].push_back(y);
		vec[y].push_back(x);
	}
	
	dfs(1,0);
	printf("%d",ans);
	return 0; 
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值