P2015 二叉苹果树

 P2015 二叉苹果树

题目描述

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

2 5 / 3 4 / 1 现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

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

输入输出格式

输入格式:

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

N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

输出格式:

一个数,最多能留住的苹果的数量。

输入输出样例

输入样例#1: 复制
5 2
1 3 1
1 4 10
2 3 20
3 5 20
输出样例#1: 复制
21

分析

>:<自己做出来的第一道树形动规题,纪念!!!

树形动规,+背包

如果想要保留下树枝a,那么首先要留下a的父亲的树枝。

所以:dp[u][j]以u为根的子树中留下了j条(一定是联通的),的最大价值。

那么从叶推到根即可。

转移方程:dp[u][j] = max(dp[u][j],dp[v][k]+dp[u][j-k-1]+w);

就是从子树v中选取k条树枝,从u树其他的子树中选取j-k-1条,再加上连接v的那一条 合起来 就是从树u中选j条边的最大价值。

code

 1 #include<cstdio>
 2 #include<algorithm> 
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 110;
 8 
 9 struct Edge{
10     int to,nxt,w;
11 }e[10010];
12 int head[10010],tot;
13 
14 int dp[N][N];
15 int Sum,n,m;
16 
17 inline int read() {
18     int x = 0,f = 1;char ch = getchar ();
19     for (; ch<'0'||ch>'9'; ch = getchar())
20         if (ch=='-') f = -1;
21     for (; ch>='0'&ch<='9'; ch = getchar())
22         x = x*10+ch-'0';
23     return x*f;
24 }
25 
26 inline void add_edge(int u,int v,int w) {
27     e[++tot].to = v,e[tot].w = w,e[tot].nxt = head[u],head[u] = tot;
28 }
29 
30 void dfs(int u,int fa) {
31     for (int i=head[u]; i; i=e[i].nxt) {
32         int v = e[i].to,w = e[i].w;
33         if (v==fa) continue;
34         dfs(v,u);
35         for (int j=m; j>=1; --j) 
36             for (int k=0; k<j; ++k) 
37                 dp[u][j] = max(dp[u][j],dp[v][k]+dp[u][j-k-1]+w);
38     }
39 }
40 int main() {
41     
42     n = read(),m = read();
43     for (int a,b,c,i=1; i<n; ++i) {
44         a = read(),b = read(),c = read();
45         add_edge(a,b,c),add_edge(b,a,c);
46     }
47     
48     dfs(1,0);
49     printf("%d",dp[1][m]);
50     
51     return 0;
52 }
原文地址:https://www.cnblogs.com/mjtcn/p/7730031.html