树形DP学习笔记

1.为什么会有树形DP

     正常来说,线性DP用来解决序列的问题,但是当我们维护的数据结构发生变化的时候,比如,现在我们需要对一棵树

进行DP,普通的线性DP边无法解决了,这个时候,就需要用到树形DP了

2.树形DP的应用场景

    1中的应用场景给的比较抽象,这里详细的来说一下。最经典的例子就是一个等级森严的公司召开会议,在这个公司里,

每个人都有一个对应的上司,而终极大BOSS老板则没有上级。如果一个人的直接上级(就是相当于他的父节点)出席会议

的话,那他一定不会出席。现在,问你如果有n个人缺席,那么最多有多少人出席。

   即:树形DP应用于存在依赖关系的数据结构中求最优解的问题。

3.典型例题理解算法

   传送门

题目描述

有一棵苹果树,如果树枝有分叉,一定是分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个。

输出格式

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

输入输出样例
Input #1
5 2
1 3 1
1 4 10
2 3 20
3 5 20
Output #1

21

这道题是一个典型的入门题,很经典吖。
直接在代码里讲啦QWQ
看代码之前最好先想一下,特别是细节,里面有几个地方很容易出错
码风还好不用担心:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<cmath>
 7 #define N 1000
 8 
 9 using namespace std;
10 
11 struct Node{
12     int u;
13     int v;
14     int val;
15     int last;
16 }edge[N];
17 
18 int head[N]={false},siz[N]={false},cnt_edge=0,n,q;
19 int f[N][N]={0};
20 
21 inline int Read()
22 {
23     int num=0,k=1;
24     char c=getchar();
25     while(c!='-'&&(c>'9'||c<'0')) c=getchar();
26     if(c=='-') {k=-1;c=getchar();}
27     while(c>='0'&&c<='9'){num=(num<<1)+(num<<3)+(c^48);c=getchar();}
28     return num*k;
29  } 
30  
31 inline void add_edge(int u,int v,int val)
32 {
33     edge[++cnt_edge].u=u;
34     edge[cnt_edge].v=v;
35     edge[cnt_edge].val=val;
36     edge[cnt_edge].last=head[u];
37     head[u]=cnt_edge;
38 }
39 
40 inline void TDP(int u,int fa)
41 {
42     for(int i=head[u];~i;i=edge[i].last)//~i的意思是i!=-1 
43     {
44         int v=edge[i].v;
45         if(v==fa) continue;
46         TDP(v,u);siz[u]+= siz[v]+1;//要加上连到自己的边 
47         for(int j=min(siz[u],q);j;j--)//01Bag Problem
48         {
49             for(int k=min(j-1,siz[v]);k>=0;k--)//允许其儿子为叶子节点 
50             {
51                 f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+edge[i].val);
52         
53             }
54         }
55     }
56 }
57 
58 int main ()
59 {
60     memset(head,-1,sizeof(head));
61     n=Read();q=Read();
62     for(int i=1;i<n;i++)
63     {
64         int u=Read();int v=Read();int w=Read();
65         add_edge(u,v,w);add_edge(v,u,w);
66     }
67     TDP(1,-1);
68     printf("%d\n",f[1][q]);
69     return 0;
70 }
View Code

 

posted @ 2020-11-27 21:45  Roy0_0  阅读(173)  评论(1编辑  收藏  举报
Live2D