Apple Tree (POJ2486

                      题目传送门

 题解:

  第一道树上背包题qaq

  考虑每个节点在最终答案中的类型:1,不经过;2,经过但不返回;3,经过且返回 (返回的定义是最终的停止节点不位于该节点的子树中)

  对于第一种类型的节点,不用考虑。

  对于后两种类型,我们设f[i][j][0]表示在第i个节点的子树中走j步且最终回到i节点所能够获得的最大权值,f[i][j][1]表示最终不回到i节点获得的最大权值。

  对于一个节点的每一个子节点,都要选择其中的一种状态。我们可以把该问题抽象成分组背包问题:一个容量为j的背包,有siz组物品(siz相当于子节点数目),每组物品只能选一种。那么我们可以得到状态转移方程: 

  f[i][j][0] = max{f[v][k][0]+f[i][j-k-2][0]} (既然要回到该节点,那么对于子节点v来说肯定也要回到v节点,且下去上来各一步,故多用掉两步)

  f[i][j][1] = max{f[v][k][0]+f[i][j-k-2][1]} (对于v节点来说,下去不回来,那么其他的节点下去后就必须回来)

  f[i][j][1] = max{f[v][k][1]+f[i][j-k-1][0]} (该节点回来,那么其他节点可以不回来)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define LL long long
 5 #define RI register int
 6 using namespace std;
 7 const int INF = 0x7ffffff ;
 8 const int N = 100 + 10 ;
 9 const int K = 200 + 10 ;
10 
11 inline int read() {
12     int k = 0 , f = 1 ; char c = getchar() ;
13     for( ; !isdigit(c) ; c = getchar())
14       if(c == '-') f = -1 ;
15     for( ; isdigit(c) ; c = getchar())
16       k = k*10 + c-'0' ;
17     return k*f ;
18 }
19 
20 struct Edge {
21     int to, next ;
22 }e[N<<1] ;
23 int n, k, cnt = 0 ; int head[N], w[N], f[N][K][2] ;  // 0表示回来,1表示不回来 
24 inline void add_edge(int x,int y) {
25     e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt ;
26 }
27 
28 void dfs(int x,int fa) {
29     for(int j=0;j<=k;j++) f[x][j][0] = f[x][j][1] = w[x] ;
30     for(int i=head[x];i;i=e[i].next) {
31         int y = e[i].to ; if(y == fa) continue ;
32         dfs(y,x) ;
33         for(int j=k;j>=0;j--) {
34             for(int kk=0;kk<=j;kk++) {
35                 if(j >= kk+2) f[x][j][0] = max(f[x][j][0],f[x][j-kk-2][0]+f[y][kk][0]) ;
36                 if(j >= kk+2) f[x][j][1] = max(f[x][j][1],f[x][j-kk-2][1]+f[y][kk][0]) ;
37                 if(j >= kk+1) f[x][j][1] = max(f[x][j][1],f[x][j-kk-1][0]+f[y][kk][1]) ;
38             }
39         }
40     }
41 }
42 
43 int main() {
44     while(~scanf("%d %d",&n,&k)) {
45         cnt = 0 ; memset(head,0,sizeof(head)) ;
46         for(int i=1;i<=n;i++) w[i] = read() ;
47         for(int i=1;i<n;i++) {
48             int x = read(), y = read() ;
49             add_edge(x,y) ; add_edge(y,x) ;
50         }
51         dfs(1,0) ;
52         printf("%d
",max(f[1][k][0],f[1][k][1])) ;
53      }
54      return 0 ;
55 }

   第一次就错在了子节点中只能有一个下去不回来qwq

原文地址:https://www.cnblogs.com/zub23333/p/8758891.html