二叉苹果树(codevs 5565)树形DP
题目描述 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.
思路:给出的节点没有父子关系,需要建双向边走dfs的时候判断,这部分由其注意,要先判断是否回父,在更新父亲节点
代码如下
#include<stdio.h> #include<algorithm> using namespace std; int n,q,cnt,f[210][210],fa[210],first[210]; struct Edge{ int to,next,val; }edge[210]; void add(int from,int to,int val) { edge[++cnt].to=to; edge[cnt].val=val; edge[cnt].next=first[from]; first[from]=cnt; } void dfs(int from) { for(int i=first[from];i;i=edge[i].next) { int to=edge[i].to; if(to == fa[from]) continue; fa[to]=from; dfs(to); for(int j=q;j>=1;--j)//采用倒推,j为总边数 for(int k=0;k<j;++k)//k为子节点支数,不能超过总支数 f[from][j]=max(f[from][j],f[to][k]+f[from][j-k-1]+edge[i].val);//f[to][k] 子节点拥有 k 支时的 val, f[from][j-k-1] 父节点剩余支的 val,edge[i].val当前支的val } } int main() { scanf("%d%d",&n,&q); for(int i=1;i<n;++i) { int from,to,val; scanf("%d%d%d",&from,&to,&val); add(from,to,val); add(to,from,val); } dfs(1); printf("%d",f[1][q]); return 0; }
从0到1很难,但从1到100很容易