POJ 2486 Apple Tree (树形DP,树形背包)

题意:给定一棵树图,一个人从点s出发,只能走K步,每个点都有一定数量的苹果,要求收集尽量多的苹果,输出最多苹果数。

思路:

  既然是树,而且有限制k步,那么树形DP正好。

  考虑1个点的情况:(1)可能在本子树结束第k步(2)可能经过了j步之后,又回到本节点(第k步不在本子树)

  第二种比较简单,背包一下,就是枚举给本节点的孩子t多少步,收集到最多苹果数。第一种的话要求第k步终止于本节点下的某个子树中,那么只能在1个孩子子树中,所以应该是【其他孩子全部得走回来】+【本孩子不要求走回来】   or   【其他某个孩子中不走回来】+【本节点走回来】。

  用两个DP数组区分下“回”与“不回”就行了,注意,“不回”只能有1个孩子不要求其走回来,“回”是全部回。而“不要求回来”收集到的苹果数必定大于等于“要求回来”。

 1 //#include <bits/stdc++.h>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #define pii pair<int,int>
 6 #define INF 0x3f3f3f3f3f3f3f3f
 7 #define LL  long long
 8 using namespace std;
 9 const int N=210;
10 struct node
11 {
12     int from,to,next;
13     node(){};
14     node(int from,int to,int next):from(from),to(to),next(next){};
15 }edge[N*2];
16 int edge_cnt, head[N], w[N];
17 void add_node(int from,int to)
18 {
19     edge[edge_cnt]=node(from, to, head[from]);
20     head[from]=edge_cnt++;
21 }
22 /*
23     dp[][][1]   记录每次都回到本节点的。
24     dp[][][0]   记录仅1次不回到本节点的。
25 */
26 int dp[N][N][2];
27 void DFS(int t,int far,int m)
28 {
29     node e;
30     for(int j=0; j<=m; j++)    dp[t][j][0]=dp[t][j][1]=w[t];    //既然能到这,至少带上本节点
31     if(m==0)     return;
32     for(int i=head[t]; i!=-1; i=e.next)
33     {
34         e=edge[i];
35         if( e.to^far )
36         {
37             DFS(e.to, t, m-1);
38             for(int j=m; j>0; j-- )
39             {
40                 for(int k=0; k+2<=j; k++ )
41                 {
42                     //所有分支都回。
43                     dp[t][j][1]=max( dp[t][j][1], dp[t][j-k-2][1]+dp[e.to][k][1] );
44                     //本分支要回,但在其他分支不回。因为已经有1个不回了,所以更新在‘[0]’中。
45                     dp[t][j][0]=max( dp[t][j][0], dp[t][j-k-2][0]+dp[e.to][k][1] );
46                 }
47                 for(int k=0; k+1<=j; k++ )
48                 {
49                     //不回,但其他分支就必须全回。
50                     dp[t][j][0]=max( dp[t][j][0], dp[t][j-k-1][1]+dp[e.to][k][0] );
51                 }
52             }
53         }
54     }
55 }
56
57
58
59 int main()
60 {
61     //freopen("input.txt", "r", stdin);
62     int n, K, a, b;
63     while(~scanf("%d%d",&n,&K))
64     {
65         edge_cnt=0;
66         memset(head, -1, sizeof(head));
67
68         for(int i=1; i<=n; i++) scanf("%d",&w[i]);
69         for(int i=1; i<n; i++)
70         {
71             scanf("%d%d",&a,&b);
72             add_node(a,b);
73             add_node(b,a);
74         }
75         DFS(1, -1, K);
76         cout<<dp[1][K][0]<<endl;
77     }
78     return 0;
79 }

AC代码

时间: 2024-10-24 22:08:32

POJ 2486 Apple Tree (树形DP,树形背包)的相关文章

[Poj 2486] Apple Tree 树形DP

Apple Tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9069 Accepted: 3016 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amount of

POJ 2486 Apple Tree (树形dp 经典题)

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7784   Accepted: 2603 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun

POJ 2486 Apple Tree

很好也很烦的一个树形DP,昨天搞了一晚上是在想不出,后来没办法去看题解了,完事发现非常令人感动的是,我一开始设的状态都错了,然后就一直错了下去,还好及时的回头是岸了. 不说废话了,正题: 题目大意:给一棵树,n个节点,每个节点有一个权值,要求从节点1出发最多走k步,求所经过的点的权值和的最大值,每个点经过一次后就变为0: 最近做了一些树DP 也小小的总结了点规律,树形dp一般是设dp[rt][j]即以rt为根的子树j状态.这个题可以设 dp[rt][j][0]表示以rt为根的子树走j步最后不回到

POJ 2486 Apple Tree 树形DP+分组背包

链接:http://poj.org/problem?id=2486 题意:一棵(苹果)树,树上有N个结点(N<=100),起点是结点1.每个结点上有若干个苹果,我可以进行K步操作(K<=200),每次操作是从当前结点移动到相邻的结点,并且到了相邻的结点以后会吃掉上面的所有苹果并且苹果不再长出来,相邻是指两个结点之间有边相连.问在K步操作之后最多可以吃掉多少个苹果. 思路:刚入手的时候觉得是一般的树形背包问题,dp[i][j]代表的是以i为根的子树中走j个结点所能吃到的苹果数,来进行状态转移,但

POJ 2486 Apple Tree (树形dp)

这是一个树上的背包转移.注意要用dp[i][j][k]表示第i个节点用了j的路程是否回到i节点,k=0表示回到i点,k=1表示不回到i点.那么实际上就是树上的一个背包转移. #include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <string> #include <cctype> #include

POJ 2486 Apple Tree ( 树型DP )

#include <iostream> #include <cstring> #include <deque> using namespace std; #define SIZE 230 #define BACK 1 #define AWAY 0 int DP[SIZE][SIZE][2]; bool visits[SIZE]; int vals[SIZE]; deque< int > tree[SIZE]; int num, steps; void dfs

POJ 2486 Apple Tree ——(树型DP)

题意是给出一棵树,每个点都有一个权值,从1开始,最多走k步,问能够经过的所有的点的权值和最大是多少(每个点的权值只能被累加一次). 考虑到一个点可以经过多次,设dp状态为dp[i][j][k],i表示当前从i出发,j表示最多走j步,k=0的话表示最后回到i点,否则不回到i点的子问题的答案. 转移见代码. 值得注意的是dfs中j循环的方向必须从大到小,因为如果从小到大,当前的j是从比其小的dp[u][j-t][...]更新过来的,而后者是根据走了v以后的更新过来的.换言之,如果从小到大,那么,走v

poj 3345 Bribing FIPA 【树形dp + 01背包】

Bribing FIPA Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4274   Accepted: 1337 Description There is going to be a voting at FIPA (Fédération Internationale de Programmation Association) to determine the host of the next IPWC (Interna

hdu4003 树形dp+分组背包

http://acm.hdu.edu.cn/showproblem.php?pid=4003 Problem Description Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on