URAL_1018 二叉苹果树

【题目描述】

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。

【输入格式】

第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。

【输出格式】

剩余苹果的最大数量。

input

5 2

1 3 1

1 4 10

2 3 20

3 5 20

output

21

 

思路:树形动态规划。先用结构体建树,然后保存信息。这里要注意一条边的苹果是下面节点的w值(1号节点只需补上一条w为0的边即可),然后递归动态规划,f[i][j]代表i为根节点时保留j个树枝的最大苹果数

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int n,q;
bool vis[1005];
int a[15],b[15],c[15];
int f[1005][1005];
struct node{
int l,r,w;
}m[1005];
void buildtree(int x)
{
  vis[x]=true;
  for(int i=1;i<=n-1;i++)
  {
    if(a[i]==x||b[i]==x)
    {
      int k=a[i]+b[i]-x;
      if(vis[k]==true)continue;
      if(m[x].l==0)
      {
        m[x].l=k;m[k].w=c[i];
        buildtree(k);
      }
      else
      {
        m[x].r=k;m[k].w=c[i];
        buildtree(k);
      }
    }
  }
}
void dp(int k)
{
  f[k][1]=m[k].w;
  if(m[k].l==0)return ;
  dp(m[k].l);
  dp(m[k].r);
  for(int i=1;i<=q+1;i++)
  for(int j=0;j<=i-1;j++)
  {
    if(f[k][i]<f[k][1]+f[m[k].l][j]+f[m[k].r][i-j-1])
    f[k][i]=f[k][1]+f[m[k].l][j]+f[m[k].r][i-j-1];
  }
}
int main()
{
  memset(vis,false,sizeof(vis));
  cin>>n>>q;
  for(int i=1;i<=n-1;i++)
  cin>>a[i]>>b[i]>>c[i];
  buildtree(1);
  dp(1);
  cout<<f[1][q+1];
  return 0;
}

原文地址:https://www.cnblogs.com/937337156Zhang/p/5675836.html