poj2486 Apple Tree

题目大意:有一颗n个节点的树,每个节点上有一些数量的苹果,Wshxzt从1号节点出发,每经过一条边算走一步,问走k不最多可以吃掉多少苹果;

 

思路:树形dp,背包问题,设dp1[i][j]为从i节点出发,走j步然后回到i节点所能吃到的最多苹果树,dp2[i][j]为从i节点出发,走j步可能不回到i节点所能吃到的苹果树

 

对于dp1[i][j]由于必须回到i号节点,所以如果访问了i的某个儿子,则i到这个儿子的边走了两次,

对于dp2[i][j],由于不回到i节点,所以有两种情况,对于某个儿子节点v,可能最后在v的子树中,也可能在出v外其他的子树中,对于第一种情况,i->v的边走1次,第二种情况走两次;

 

状态转移方程:

dp1[s][j+2]=max(dp1[s][j+2],dp1[s][j-t]+dp1[v][t]);//回到i节点
dp2[s][j+1]=max(dp2[s][j+1],dp1[s][j-t]+dp2[v][t]);//不回到i节点,最后在以v为根的子树中;所以访问v前必须回到了i节点,也就是dp1[s][j-t];
dp2[s][j+2]=max(dp2[s][j+2],dp2[s][j-t]+dp1[v][t]);//不回到i节点,最后在v之外的其他子树种,所以访问v之后可能有到了其他子树种结束,也就是dp2[s][j-t];

 

代码如下;

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#define LL long long

using namespace std;
int n,k;
int head[111],size,key[222],next[222];
int value[111];
int dp1[111][222];
int dp2[111][222];
void add(int u,int v){
	key[size]=v;next[size]=head[u];head[u]=size++;	
}
void solve(int s,int pa){
	for(int i=0;i<=k;++i)dp1[s][i]=dp2[s][i]=value[s];
	for(int i=head[s];~i;i=next[i]){
		int v = key[i];
		if(v==pa)continue;
		solve(v,s);
		for(int j=k;j>=0;--j){
			for(int t = 0;t<=j;++t){
				dp1[s][j+2]=max(dp1[s][j+2],dp1[s][j-t]+dp1[v][t]);
				dp2[s][j+1]=max(dp2[s][j+1],dp1[s][j-t]+dp2[v][t]);
				dp2[s][j+2]=max(dp2[s][j+2],dp2[s][j-t]+dp1[v][t]);
			}
		}
	}
}
int main(){
	while(cin>>n>>k){
		size = 0 ;memset(head,-1,sizeof(head));	
		for(int i=1;i<=n;++i)cin>>value[i];
		int u,v;
		for(int i=1;i<n;++i){
			cin>>u>>v;
			add(u,v);add(v,u);	
		}
		memset(dp1,0,sizeof(dp1));
		memset(dp2,0,sizeof(dp2));
		solve(1,0);
		cout<<max(dp1[1][k],dp2[1][k])<<endl;
	}
	return 0;
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值