博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
codevs 5565 二叉苹果树 树形DP
阅读量:4982 次
发布时间:2019-06-12

本文共 2339 字,大约阅读时间需要 7 分钟。

5565 二叉苹果树

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 黄金 Gold
 
题目描述 Description

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

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

 

输入描述 Input Description

    第1行2个数,N和Q(1<=Q<= N,1<N<=100)。

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

 

输出描述 Output Description

剩余苹果的最大数量。

 

样例输入 Sample Input

5 2

1 3 1

1 4 10

2 3 20

3 5 20

 

样例输出 Sample Output

21

 

数据范围及提示 Data Size & Hint

对于20%数据 n<=20;

对于100%数据1<N<=100,1<=Q<= N.

 --------------------------------------------------------------------------------------------------------------------------------------------

很简单的一道树形DP,思路是 先把二叉树各边边权值转移到子节点上(这么做才能确定各点的状态),这样点x的状态即 点x的子树(包括点x)上保留y个点所得的最大值,开二维数组储存状态即dp[x][y],然后一遍DFS确定dp[x][1]的值,即等于点x的权值,然后在回溯时进行状态转移,不难得出状态转移方程为:

dp[x][i]=max(dp[l[x]][j]+dp[r[x]][i-j-1]+dp[x][1],dp[x][i])。但要注意的问题是,最后还要对根节点进行一次状态转移:dp[1][Q]=max(dp[l[1]][i]+dp[r[1]][Q-i],dp[1][Q]),因为点权之前是由边权转移而来,而根节点没有参与边权的转移,故需要分开来。AC代码:

1 #include
2 #include
3 #define maxn 233 4 struct node{ 5 int to,next,w; 6 }; 7 node e[maxn]; 8 int N,Q,dp[maxn][maxn],pre[maxn],cnt,l[maxn],r[maxn]; 9 bool vis[maxn];10 int read();11 int max(int,int);12 void dfs(int);13 void build(int,int,int);14 int main(){15 memset(dp,0,sizeof(dp));16 memset(vis,0,sizeof(vis));17 memset(dp,0,sizeof(dp));18 N=read();Q=read();cnt=0;19 for(int i=1;i
c||c>'9'){
if(c=='-')f=-1;c=getchar();}32 while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;33 }34 void build(int x,int y,int z){35 e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;e[cnt].w=z;36 e[++cnt].to=x;e[cnt].next=pre[y];pre[y]=cnt;e[cnt].w=z;37 }38 void dfs(int x){39 if(!vis[x]){40 vis[x]=1;41 bool po=1;42 for(int i=pre[x];i;i=e[i].next){43 int to=e[i].to;44 if(!vis[to]){45 dp[to][1]=e[i].w;46 if(po)l[x]=to,po=0;47 else r[x]=to; 48 }49 dfs(to);50 }51 for(int i=2;i<=Q;i++)52 for(int j=0;j
y?x:y;58 }
二叉苹果树

其实自己还有一个思路,就是把状态定为 x点的子树中保留y条边时的最大值,这样就可以只有一条状态转移方程,但个人觉得处理起来没有第一种思路好。

转载于:https://www.cnblogs.com/lpl-bys/p/7384402.html

你可能感兴趣的文章
Managing Dynamic Objects in C++
查看>>
计算excel列的名字
查看>>
自助Linux之问题诊断工具strace
查看>>
JDBC为什么要使用PreparedStatement而不是Statement
查看>>
delphi调用LUA函数来处理一些逻辑
查看>>
MySQL下分页查询数据
查看>>
解题报告 幸福的道路
查看>>
Windows Service
查看>>
数据结构小练习
查看>>
jQuery的选择器
查看>>
python time模块
查看>>
省市区联动
查看>>
省选专练POI2015Logistyka
查看>>
CCPC2016合肥现场赛
查看>>
layui 框架之秒传文件 (前端分段 MD5 型成秒传)
查看>>
Asp.net 在刷新或提交页面后保持滚动条的位置
查看>>
JVM类加载原理学习笔记
查看>>
浏览器-02 Chromium的多线程
查看>>
git如何查找某文件中每一行的修改情况?
查看>>
linux下的下载之道
查看>>