题目大意:
给出一棵树,求出从起点开始走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)
时间: 2024-10-27 02:09:53