简单树形动态规划(Ural 1018 Binary Apple Tree)

极限简单题:
二叉苹果树(apple)
Ural 1018
【问题描述】
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)。这棵树共有N个结点(叶子点或者树枝分叉点),编号为1~~N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
这里写图片描述
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。

不得不说出题人真是好人
题目最重要一个条件:
二叉!
二叉!!
二叉!!!(重要的事情说三遍)
真为我们省事

这里写图片描述
1为苹果树的根
2,3,4..就是它的叉
一条边连接的一个父亲和一个儿子
这里我们存为x和y

#include <cstdio>
#include <cstring>
using namespace std;
struct node
{
    int x,y,d,next;
    //x:这条边所连接的父亲
    //y:这条边所连接的儿子
    //d:这个叉上长了多少个苹果
    //next:上一条边的编号
}a[210];
int last[110],n,k,len=0;
//last[len]:len这个点最后一条和它相连的边的编号
struct nodetr
{
    int l,r;
    nodetr()
    {
        l=0;r=0;
    }
}tr[110];
int f[110][110];
bool bk[110];
void ins(int x,int y,int c)//建边
{
    len++;
    a[len].x=x;a[len].y=y;a[len].d=c;
    a[len].next=last[x];last[x]=len;
}
int mymax(int x,int y)
{
    return x>y?x:y;
}
void dfs(int x)//这里用了多叉树的方法来做得
{
    for (int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if (bk[y]==true)
        {
            bk[y]=false;
            f[y][1]=a[k].d;
            if (tr[x].l==0) tr[x].l=y;
            else tr[x].r=y;
            dfs(y);
        }
    }
}
int treedp(int x,int kk)//DP
{
//f[i][j]:i:到哪一个点惹;j:保留多少个点
    if (f[x][kk]!=-1) return f[x][kk];//如果已经做过就直接输出
    int maxx=0;
    for (int i=0;i<=kk-1;i++)
    {
        int ll,rr,trl,trr;
        ll=i;
        rr=kk-1-i;
        //分为左右两部分,分别保留ll个枝和rr个枝
        trl=treedp(tr[x].l,ll);
        trr=treedp(tr[x].r,rr);
        //分别DP一遍
        maxx=mymax(trl+trr+f[x][1],maxx);
    }
    f[x][kk]=maxx;
    return maxx;
}
int main()
{
    scanf("%d%d",&n,&k);
    memset(last,0,sizeof(last));
    int x,y,c;
    for (int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c);
        ins(y,x,c);
    }
    memset(f,-1,sizeof(f));
    memset(bk,true,sizeof(bk));
    bk[1]=false;
    dfs(1);
    for (int i=1;i<=n;i++) f[i][0]=0;
    f[1][1]=0;
    printf("%d\n",treedp(1,k+1));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值