【codevs】二叉苹果树 (二叉树的树形dp)

P2015 二叉苹果树

题目描述

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入输出格式

输入格式:
第1行2个数,N和Q(1<=Q<= N,1 < N<=100)。

N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

输出格式:
一个数,最多能留住的苹果的数量。

输入输出样例

输入样例#1:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
输出样例#1:
21

思路:二叉树的树形dp。 瞎搞就可以。 注:因为这道题给的两个点之间前后顺序是不一定的,所以首先判断其中一点是不是其他节点的子节点,若是,则将其作为另一节点的父亲,反之则为儿子节点。

附代码:

#include
#include
using namespace std;
struct node
{
    int l,r,v;
}tree[1001];
int flag[101];
int f[101][101];
int n,q;
int gen;
void ecs()
{
    int i,x,y,m;
    for (i=1;iint p=0;
        scanf("%d%d%d",&x,&y,&m);
        for (int j=1;j<=n;j++)
            if (tree[j].l==y||tree[j].r==y) p=1;   //因为这道题给的两个点之间前后顺序是不一定的,所以首先判断其中一点
            //是不是其他节点的子节点,若是,则将其作为另一节点的父亲,反之则为儿子节点。 
        if (p==0) 
        {
            if (tree[x].l==0) tree[x].l=y;
            else if (tree[x].r==0) tree[x].r=y;
            tree[y].v=m; 
            flag[y]=1;
        }
        else 
        {
            if (tree[y].l==0) tree[y].l=x;
            else if (tree[y].r==0) tree[y].r=x;
            tree[x].v=m;
            flag[x]=1;
        }
    }
    for (i=1;i<=n;i++)
        if (flag[i]==0) {gen=i;break;}
}
void dfs(int i,int j)
{
    int k;
    if (j==0) f[i][j]=0;
    else if (tree[i].r==0&&tree[i].l==0) f[i][j]=tree[i].v;
    else 
    {
        f[i][j]=0;
        for (k=0;kif (f[tree[i].l][k]==0) dfs(tree[i].l,k);
            if (f[tree[i].r][j-k-1]==0) dfs(tree[i].r,j-k-1);
            f[i][j]=max(f[i][j],f[tree[i].l][k]+f[tree[i].r][j-k-1]+tree[i].v);
        }
    }
}
int main()
{
    int ans;
    scanf("%d%d",&n,&q);
    ecs();
    dfs(gen,q+1);
    printf("%d",f[gen][q+1]);//q+1是因为将价值赋值给了父节点与子节点的子节点,所以最后是q+1 
}

你可能感兴趣的:(题库,dp,树形dp)