poj 2486 apple tree 树形DP 不懂的一定把你讲懂

很典型的树形DP,自己也理解了好久,感觉自己好水哦。。。。。。。。。。。。。。。。。。。。。。。。。

所以讲得清楚一点,以后回忆起来也快

题意:一颗树,n个点(1-n),n-1条边,每个点上有一个权值,求从1出发,走V步,最多能遍历到的权值

我们把背包的思想用到这里来,做的步数相当于背包的容量,点上的权值相当于价值,给定一定的背包容量,求最多能装进背包的价值

设dp[0][s][j]表示从s(当前根节点)出发,走 j 步,回到s所能获得的最大权值

   dp[1][s][j]表示从s(当前根节点)出发,走j步,不回到s所能获得的最大权值

现在我们就可以分配背包容量了:父节点与子节点分配背包容量,从而设计出状态转移方程

主要思想:

s返回,t返回   

s不返回,t返回(走向t子树,t子树返回之后走向s的其他子树,然后不回到s)

s返回,t不返回(遍历s的其他子树后返回s,返回之后走向t子树,然后不回到t)

没有都不返回,肯定有一方有一个返回的过程,再去另一边的子树的

总结起来一句话,要么去s的其他子树呆着,要么去t子树呆着,要么回到s点

1、在t子树返回,其他子树也返回,即回到当前根节点s

2,、不返回根节点,但在t子树返回,即相当于从t出发走k步返回t的最优值  加上  从s出发走j-k步到其他子树不返回的最优值,中间有s与t连接起来,其实就等于从s出发遍历t子树后(dp[0][t][k])又回到s(这一步多了中间的来回两步),再走出去(其他子树)【dp[1][s][j-k]】,不回来

3、不返回根节点,在t子树也不返回,等价于从s出发遍历其他子树,回到s(dp[0][s][j-k]),再走向t子树,不回到t(dp[1][t][k]),这个过程s-t只走了一步

dp[0][s][j+2]=Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);//从s出发,要回到s,需要多走两步s-t,t-s,分配给t子树k步,其他子树j-k步,都返回
dp[1][s][j+2]=Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);//不回到s(去s的其他子树),在t子树返回,同样有多出两步
dp[1][s][j+1]=Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);//先遍历s的其他子树,回到s,遍历t子树,在当前子树t不返回,多走一步

View Code
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
vector<int> g[1010];
int dp[2][1010][210];
int n,V,val[1010];
bool used[1010];
void Max(int &a,int b){
if(a<b) a=b;
}
void dfs(int s){
int i;
used[s]=true;
for(i=0;i<=V;i++){
dp[0][s][i]=dp[1][s][i]=val[s];//强制加入
}
for(i=0;i<g[s].size();i++){
int t=g[s][i];
if(used[t]) continue;
dfs(t);
for(int j=V;j>=0;j--){
for(int k=0;k<=j;k++){//中间的桥梁一定要走,所以把状态依次转变过来
Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);
Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);
Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);
}
}
}
}
int main(){
int i,a,b;
while(scanf("%d%d",&n,&V)!=EOF){
for(i=0;i<=1000;i++)
g[i].clear();
for(i=1;i<=n;i++)
scanf("%d",&val[i]);
for(i=0;i<n-1;i++){
scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
memset(dp,0,sizeof(dp));
memset(used,false,sizeof(used));
dfs(1);
printf("%d\n",dp[1][1][V]);
}
return 0;
}



posted @ 2012-01-09 08:11  Because Of You  Views(3438)  Comments(3Edit  收藏  举报