树形dp偷天换日题解(洛谷P3360)

题目链接:https://www.luogu.org/problem/show?pid=3360

题解:我们用f[i][j]来表示以i为根的子树上给定j的时间能获得的价值,需要记忆化搜索。

        (如果是走廊)f[i][j]=max(f[i][j],f[lson][k]+f[rson][j-k-2*time[i]);

         (如果尽头是画就进行01背包)程序具体有些细节,我在程序注释中写

程序:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int tot,m,b[500];
LL f[500][1000],a[500];
void dfs(int now)
{
  int x,y;
  scanf("%d%d",&x,&y);
  x=x*2;//因为无论如何要走的话,这条走廊是要走两遍的
  if (y) //如果说尽头是画的话,就预先处理好01背包
  {
    for (int i=1;i<=y;i++) scanf("%lld%d",&a[i],&b[i]);
    for (int i=1;i<=y;i++)
     for (int j=m;j>=b[i]+x;j--)
       f[now][j]=max(f[now][j],f[now][j-b[i]]+a[i]); 
  }
  else
  {//否则深搜左右儿子
      tot++; int l=tot; dfs(tot);
      tot++; int r=tot; dfs(tot);
      for (int i=x;i<=m;i++)
       for (int j=0;j<=i-x;j++)
         f[now][i]=max(f[now][i],f[l][j]+f[r][i-j-x]);
//进行dp
  }
}
int main()
{
  tot=1;
  scanf("%d",&m); m--; dfs(1);
  printf("%lld
",f[1][m]);
  return 0;
} 
原文地址:https://www.cnblogs.com/2014nhc/p/6625023.html