题目大意:
给出一棵树,求出从起点开始走m长度最后回到起点,所能得到的宝藏的最大价值。
思路分析:
通过一次dfs可以得到的是子树到根节点的所有距离的最大值。
现在的问题就是他走完一颗子树可以去另外一颗子树。
所以在回溯到根的时候要统计其他子树上互补距离的最大值。
dp[i] [j] 表示i为根节点,在i的子树中走j步然后回到i所能拿到的最大价值。
转移方程就是
dp[x][i+2*len]=max(dp[x][i+2*len],dp[v][j]+dp[x][i-j]);
v为x的子树的根,len 为 x-v的距离
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstring>
#define maxn 105
using namespace std;
int dp[maxn][maxn<<1];
int val[maxn];
int n,m,k;
int tot;
int head[maxn];
int next[maxn<<1];
int to[maxn<<1];
int cost[maxn<<1];
void init()
{
tot=0;
memset(head,0,sizeof head);
}
void addedge(int u,int v,int w)
{
tot++;
next[tot]=head[u];
to[tot]=v;
cost[tot]=w;
head[u]=tot;
}
bool vis[maxn];
void dfs(int x)
{
for(int i=0;i<=m;i++)
dp[x][i]=0;
for(int p=head[x];p;p=next[p])
{
int v=to[p];
if(vis[v])continue;
int len=cost[p];
vis[v]=true;
dfs(v);
for(int i=m;i>=0;i--)
{
if(i+2*len>m)continue;
for(int j=0;j<i;j++)
dp[x][i+2*len]=max(dp[x][i+2*len],dp[v][j]+dp[x][i-j]);
}
for(int i=len*2;i<=m;i++)
dp[x][i]=max(dp[x][i],dp[v][i-len*2]);
}
for(int i=0;i<=m;i++)
dp[x][i]+=val[x];
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
for(int i=2;i<=n;i++)
{
int l,r,w;
scanf("%d%d%d",&l,&r,&w);
addedge(l,r,w);
addedge(r,l,w);
}
scanf("%d%d",&k,&m);
memset(vis,false,sizeof vis);
vis[k]=true;
dfs(k);
int ans=0;
for(int i=0;i<=m;i++)
{
ans=max(ans,dp[k][i]);
}
printf("%d\n",ans);
}
return 0;
}
zoj 3626 Treasure Hunt I (树形dp),布布扣,bubuko.com
zoj 3626 Treasure Hunt I (树形dp)
原文:http://blog.csdn.net/u010709592/article/details/38678009