树形dp TELE (POJ1155)

题目链接:http://poj.org/problem?id=1155

题解:

懵。。。。

这题好像就是01背包吧

我们用f[x][j+k]来表示以x为根的子树,转播j+k个用户时,能获得的利润

f[x][j+k]=max(f[x][j+k],f[x][j]+f[son][k]-w);(w表示转播需付出的代价);

我们先处理好所有的f[son][k]然后来更新当前答案;

程序:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct ding{
    int to,l,next;
}edge[10010];
int n,m,cnt,head[5000],num[5000],dp[5000][5000],tem[5000];
void add(int u,int v,int val)
{
  edge[++cnt].to=v;edge[cnt].l=val;edge[cnt].next=head[u];head[u]=cnt;
}
void dfs(int x)
{
  for (int i=head[x];i;i=edge[i].next)
  {
    int y=edge[i].to,w=edge[i].l;
    dfs(y);
    for (int j=0;j<=num[x];j++) tem[j]=dp[x][j];
//我们要先备份,因为在更新过程中,使用到的dp[x][j]也会被更新
    for (int j=0;j<=num[x];j++)
     for (int k=0;k<=num[y];k++)
       dp[x][j+k]=max(dp[x][j+k],tem[j]+dp[y][k]-w);
//更新
    num[x]+=num[y];
//一个剪枝,有几个叶子节点,我们就没举几个
  }
}
int main()
{
  int k,x,y;
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n-m;i++)
  {
    scanf("%d",&k);
    for (int j=1;j<=k;j++)
    {
      scanf("%d%d",&x,&y);
      add(i,x,y);
    }
  } 
  for (int i=n;i>=1;i--)
   for (int j=1;j<=m;j++)
   dp[i][j]=-210000000;
  for (int i=n-m+1;i<=n;i++) 
  {
    scanf("%d",&dp[i][1]);
//预处理
    num[i]=1;
  }
  dfs(1);
  for (int i=m;i>=0;i--)
  if (dp[1][i]>=0)
//如果不亏钱的话
  {
    printf("%d
",i);
    break;
  } 
  return 0;
} 
原文地址:https://www.cnblogs.com/2014nhc/p/6625645.html