hihocoder-1055 刷油漆(树形DP)

原创 2015年11月20日 20:19:20

刷油漆:http://hihocoder.com/problemset/problem/1055


时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

上回说到,小Ho有着一棵灰常好玩的树玩具!这棵树玩具是由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不同的数字,并且这些数字都是处于1..N的范围之内,每根木棍都连接着两个不同的小球,并且保证任意两个小球间都不存在两条不同的路径可以互相到达。没错,这次说的还是这棵树玩具的故事!

小Ho的树玩具的质量似乎不是很好,短短玩了几个星期,便掉漆了!

“简直是一场噩梦!”小Ho拿着树玩具眼含热泪道。

“这有什么好忧伤的,自己买点油漆刷一刷不就行了?”小Hi表示不能理解。

“还可以这样?”小Ho顿时兴高采烈了起来,立马跑出去买回来了油漆,但是小Ho身上的钱却不够——于是他只买回了有限的油漆,这些油漆最多能给M个结点涂上颜色,这就意味着小Ho不能够将他心爱的树玩具中的每一个结点都涂上油漆!

小Ho低头思索了半天——他既不想只选一部分结点补漆,也不想找小Hi借钱,但是很快,他想出了一个非常棒的主意:将包含1号结点的一部分连通的结点进行涂漆(这里的连通指的是这一些涂漆的结点可以互相到达并且不会经过没有涂漆的结点),然后将剩下的结点拆掉!

那么究竟选择哪些结点进行涂漆呢?小Ho想了想给每个结点都评上了分——他希望最后留下来,也就是涂漆了的那些结点的评分之和可以尽可能的高!

那么,小Ho该如何做呢?

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个整数N、M,意义如前文所述。

每组测试数据的第二行为N个整数,其中第i个整数Vi表示标号为i的结点的评分

每组测试数据的第3~N+1行,每行分别描述一根木棍,其中第i+1行为两个整数Ai,Bi,表示第i根木棍连接的两个小球的编号。

对于100%的数据,满足N<=10^2,1<=Ai<=N, 1<=Bi<=N, 1<=Vi<=10^3, 1<=M<=N

小Hi的Tip:那些用数组存储树边的记得要开两倍大小哦!

输出

对于每组测试数据,输出一个整数Ans,表示使得涂漆结点的评分之和最高可能是多少。



样例输入
10 4
370 328 750 930 604 732 159 167 945 210 
1 2
2 3
1 4
1 5
4 6
4 7
4 8
6 9
5 10
样例输出
2977

第一次做树形DP,以前听过也找到过各种讲解,可是本身DP不太好,所以不敢接触...

实际做一次发现其实很好理解,只不过是将DP过程放在后序遍历中


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct Node {
    int e,nxt;
}node[205];//数组模拟链表

int n,m,num;
int h[105];
int dp[105][105];//dp[i][j]表示以i为根结点,选出包含根节点的j个节点,这样的选法最高的评分

void add(int s,int e) {//加边
    node[++num].e=e;
    node[num].nxt=h[s];
    h[s]=num;
}

void dfs(int u,int pre) {
    int p=h[u],i,j;
    while(p) {
        if(node[p].e!=pre) {
            dfs(node[p].e,u);//先对树u的子树进行dp
            for(i=m;i>=2;--i)//这里i递减是为了用到上一个子树产生的dp值,如果反过来就会用到本次子树产生的dp值,导致一个结点被多次涂油漆,差不多与01背包和完全背包的区别一样
                for(j=1;j<i;++j)
                    dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[node[p].e][j]);//对树u进行dp
        }
        p=node[p].nxt;
    }
}

int main() {
    int s,e,i;
    while(2==scanf("%d%d",&n,&m)) {
        memset(h,0,sizeof(h));
        memset(dp,0,sizeof(dp));
        num=0;
        for(i=1;i<=n;++i)
            scanf("%d",&dp[i][1]);
        for(i=1;i<n;++i) {
            scanf("%d%d",&s,&e);
            add(s,e);
            add(e,s);
        }
        dfs(1,0);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

基于树的动态规划

问题描述很多时候,我们所做的DP(Dynamic Programming)通常是基于很简单的数据结构,比如一维数组、二维数组、甚至更高维的数组。今天刷 hihocoder的时候,遇到了一道题,很有意思...
  • nisxiya
  • nisxiya
  • 2015年04月23日 17:02
  • 644

刷油漆(树形dp)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho有着一棵灰常好玩的树玩具!这棵树玩具是由N个小球和N-1根木棍拼凑而成,这N个小球...
  • qq_32036091
  • qq_32036091
  • 2016年05月03日 09:01
  • 274

树形 DP 总结

一、介绍 1、什么是树型动态规划  顾名思义,树型动态规划就是在“树”的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有...
  • AngOn823
  • AngOn823
  • 2016年08月27日 14:12
  • 1646

树形DP总结,持续更新

树形DP总结,持续更新
  • Dacc123
  • Dacc123
  • 2016年01月03日 18:09
  • 403

树形DP—依赖背包模板

void DP(int x){ for(int i=0;i
  • xlzhang223
  • xlzhang223
  • 2016年03月12日 12:25
  • 236

树形动态规划(树状DP)小结

树状动态规划定义 之所以这样命名树规,是因为树形DP的这一特殊性:没有环,dfs是不会重复,而且具有明显而又严格的层数关系。利用这一特性,我们可以很清晰地根据题目写出一个在树(型结构)上的记忆化搜索...
  • txl16211
  • txl16211
  • 2015年04月29日 23:10
  • 9869

树形dp 小结

只能勉强称之为树形dp的傻逼问题:[POJ1655]Balancing Act 树的重心,经典问题,但是非常简单啊。。。 用size维护一下就好辣! [BZOJ2435][Noi2011]道路修...
  • Clove_unique
  • Clove_unique
  • 2016年11月17日 22:32
  • 559

树形动态规划(树形DP)入门问题—初探 & 训练

树形DP入门 poj 2342 Anniversary party   先来个题入门一下~ 题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的...
  • txl16211
  • txl16211
  • 2015年04月29日 22:40
  • 9965

hdoj1561The more, The Better(树形dp,依赖背包)

题目:hdoj1561The more, The Better 题意:ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得...
  • y990041769
  • y990041769
  • 2014年07月23日 17:57
  • 3173

树形DP整理小结

树形DP: 在树上进行dp,树是递归的定义的,所以树形dp也是递归的求解,一般而言,dp[node]表示的是以node为根的子树能得到的最优解 一般而言,dp[node]需要从node的子结点进行状态...
  • tomorrowtodie
  • tomorrowtodie
  • 2016年08月24日 15:38
  • 983
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hihocoder-1055 刷油漆(树形DP)
举报原因:
原因补充:

(最多只允许输入30个字)