Ural 1018 binary apple tree(显性树的树dp)

题意:一棵含n个节点的树,保留m条边,使含m条边的子树的边权和最大;

思路:树dp.求含m+1个节点边权和最大的子树。对每个分支节点有三种操作:剪去左子树;剪去右子树;将其节点数合理分配给左右子树;

记以x为根,含k个节点的子树的最大边权和为g[x][k]。

若x为叶节点,则g[x][k]为x通往父节点的边权;若非叶节点,枚举k-1个节点分配在左右子树的所有可能方案,找到最佳方案;

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 256
#define MAX(a,b) (a>b?a:b)
using namespace std;
int n,m,ne,x,y,z;
//节点数为n,要保留的树枝数为m,边序号为ne,树枝边为(x,y),权为z
int id[N],w[N],v[N],next[N],head[N],lch[N],rch[N],f[N];
//第i条边的邻接点为id[i],边权为w[i],后继指针为next[i],节点x的邻接表指针为head[x],二叉树中节点i的左右儿子lch[i],rch[i]
//父亲为f[i],通往父节点的边权为v[i]
int g[N][N];  //状态转移方程
void add(int x,int y,int z)     //将边权为z的树枝边(x,y)加入邻接表
{
    id[++ne]=y;
    w[ne]=z;
    next[ne]=head[x];
    head[x]=ne;
}
void dfs(int x)    //从节点x出发,构造二叉树
{
    for(int p=head[x];p;p=next[p]) //搜索x的所有邻接边p
    if(id[p]!=f[x])        //若边p的邻接点非x的父亲,则作为x的左或右儿子
    {
        if(!lch[x]) lch[x]=id[p];
        else rch[x]=id[p];
        f[id[p]]=x;v[id[p]]=w[p];
        dfs(id[p]);        //x作为边p的邻接点的父亲,设定边权,继续递归边p的邻接点
    }
}
int dp(int x,int k)        //从x出发,构造含k个节点且能留住最多苹果数的子树
{
    if(!k) return 0;
    if(g[x][k]>=0) return g[x][k];  //返回结果
    if(!lch[x]) return (g[x][k]=v[x]);  //若x为叶子,则返回x通往父节点的边权
    for(int i=0;i<k;i++)    //计算k个节点分配在左右子树的最佳方案
        g[x][k]=MAX(g[x][k],dp(lch[x],i)+dp(rch[x],k-i-1));
    g[x][k]+=v[x];          //计入x通往父节点的边权
    return g[x][k];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z); //构造邻接表
    }
    dfs(1);  //从1出发,构造二叉树
    memset(g,255,sizeof(g));
    printf("%d\n",dp(1,m+1)); //从节点1出发,计算含m+1个节点且能留住最多苹果数的子树,返回最多苹果数
    return 0;
}
时间: 2024-11-11 18:53:36

Ural 1018 binary apple tree(显性树的树dp)的相关文章

ural 1018 Binary Apple Tree

1018. Binary Apple Tree Time limit: 1.0 secondMemory limit: 64 MB Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a binary tree, i.e. any biparous branch splits up to exactly two new branches. We will enu

URAL 1018 Binary Apple Tree 树形DP 好题 经典

1018. Binary Apple Tree Time limit: 1.0 secondMemory limit: 64 MB Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a binary tree, i.e. any biparous branch splits up to exactly two new branches. We will enu

timus 1018. Binary Apple Tree

1018. Binary Apple Tree Time limit: 1.0 secondMemory limit: 64 MB Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a binary tree, i.e. any biparous branch splits up to exactly two new branches. We will enu

BNUOJ 13358 Binary Apple Tree

Binary Apple Tree Time Limit: 1000ms Memory Limit: 16384KB This problem will be judged on Ural. Original ID: 101864-bit integer IO format: %lld      Java class name: (Any) Let's imagine how apple tree looks in binary computer world. You're right, it

URAL1018 Binary Apple Tree

Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a binary tree, i.e. any biparous branch splits up to e

URAL_1018 Binary Apple Tree 树形DP+背包

这个题目给定一棵树,以及树的每个树枝的苹果数量,要求在保留K个树枝的情况下最多能保留多少个苹果 一看就觉得是个树形DP,然后想出 dp[i][j]来表示第i个节点保留j个树枝的最大苹果数,但是在树形过程中,有点难表示转移 后来看了下大神的做法才知道其实可以用背包来模拟 树枝的去留,其实真的是个背包诶,每个子树枝就相当于物品,他占用了多少树枝量,带来多少的收益,就是用背包嘛,于是用树形DP+背包就可以做了 #include <iostream> #include <cstdio> #

POJ 3321 Apple Tree (dfs+线段树)

题目大意: 修改树上的节点,然后求子树的和. 思路分析: dfs 重新编号,烂大街了... #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define maxn 100005 #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e using namespace std

POJ-3321 Apple Tree 【DFS序+树状数组】

Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by branches.

POJ3321 - Apple Tree DFS序 + 线段树或树状数组

Apple Tree:http://poj.org/problem?id=3321 题意: 告诉你一棵树,每棵树开始每个点上都有一个苹果,有两种操作,一种是计算以x为根的树上有几个苹果,一种是转换x这个点上的苹果,就是有就去掉,没有就加上. 思路: 先对树求一遍dfs序,每个点保存一个l,r.l是最早到这个点的时间戳,r是这个点子树中的最大时间戳,这样就转化为区间问题,可以用树状数组,或线段树维护区间的和. #include <algorithm> #include <iterator&