POJ 2486

因为苹果可能在不同的子树中,所以,很容易想到设状态dp_back[i][j]为以i点为树根走j步并回到i点的最大苹果数与dp_to[i][j]不回到i点的两个状态。

于是,转移方程就很明显了。只是注意要减去一来一回,或者不回的边。树形DP里套背包。

但这题远比这复杂,个人认为。因为在实现上细节太多。

实现代码1:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <vector>
 4 using namespace std;
 5
 6 const int MAX=105;
 7 vector<int>G[MAX];
 8 int num[MAX],dp_back[MAX][MAX*2],dp_to[MAX][MAX*2];
 9 int tback[MAX*2],tto[MAX*2];
10 int n,s;
11
12 void init(){
13     for(int i=1;i<=n;i++)
14     G[i].clear();
15     memset(dp_back,0,sizeof(dp_back));
16     memset(dp_to,0,sizeof(dp_to));
17 }
18
19 void dfs(int u,int f){
20     int size=G[u].size();
21     for(int i=0;i<size;i++){
22         int v=G[u][i];
23         if(v!=f){
24             dfs(v,u);
25             for(int p=1;p<=s;p++){
26                 tback[p]=dp_back[u][p];
27                 tto[p]=dp_to[u][p];
28                 for(int k=0;k<=p;k++){
29                     if(p-k-2>=0){
30                         tback[p]=max(tback[p],dp_back[u][p-k-2]+dp_back[v][k]+num[v]);
31                     }
32                     if(p-k-1>=0){
33                         tto[p]=max(tto[p],dp_back[u][p-k-1]+dp_to[v][k]+num[v]);
34                     }
35                     if(p-k-2>=0){
36                         tto[p]=max(tto[p],dp_to[u][p-k-2]+dp_back[v][k]+num[v]);
37                     }
38                 }
39             }
40             for(int j=0;j<=s;j++){
41                 dp_back[u][j]=tback[j];
42                 dp_to[u][j]=tto[j];
43             }
44         }
45     }
46 }
47
48 int main(){
49     int u,v;
50     while(scanf("%d%d",&n,&s)!=EOF){
51         init();
52         for(int i=1;i<=n;i++)
53         scanf("%d",&num[i]);
54         for(int i=1;i<n;i++){
55             scanf("%d%d",&u,&v);
56             G[u].push_back(v);
57             G[v].push_back(u);
58         }
59         dfs(1,0);
60         int ans=max(dp_to[1][s],dp_back[1][s]);
61         ans+=num[1];
62         printf("%d\n",ans);
63     }
64     return 0;
65 }

这是我WA了N久后看了别人的改过来的,每次在DP时才把根节点的值加上。说不清为什么,但是对了。

另一个是我原本WA的代码,可以把OJ的讨论板所有数据都过了,但依然WA,后来研究了好久,发现自己代码上的一个问题,那就是当最大步数超过边数的两倍时,就会出现问

题,于是,我只好投机一点,最后扫描一次结果值来获得正确值了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <vector>
 4 using namespace std;
 5
 6 const int MAX=105;
 7 vector<int>G[MAX];
 8 int num[MAX],dp_back[MAX][MAX*2],dp_to[MAX][MAX*2];
 9 int tback[MAX*2],tto[MAX*2];
10 int n,s;
11
12 void init(){
13     for(int i=1;i<=n;i++)
14     G[i].clear();
15     memset(dp_back,0,sizeof(dp_back));
16     memset(dp_to,0,sizeof(dp_to));
17 }
18
19 void dfs(int u,int f){
20     int size=G[u].size();
21     dp_back[u][0]=num[u];
22     dp_to[u][0]=num[u];
23     for(int i=0;i<size;i++){
24         int v=G[u][i];
25         if(v!=f){
26             dfs(v,u);
27             for(int p=0;p<=s;p++){
28                 tback[p]=dp_back[u][p];
29                 tto[p]=dp_to[u][p];
30                 for(int k=0;k<=p;k++){
31                     if(p-k-2>=0){
32                         tback[p]=max(tback[p],dp_back[u][p-k-2]+dp_back[v][k]);
33                     }
34                     if(p-k-1>=0){
35                         tto[p]=max(tto[p],dp_back[u][p-k-1]+dp_to[v][k]);
36                     }
37                     if(p-k-2>=0){
38                         tto[p]=max(tto[p],dp_to[u][p-k-2]+dp_back[v][k]);
39                     }
40                 }
41             }
42             for(int j=0;j<=s;j++){
43                 dp_back[u][j]=tback[j];
44                 dp_to[u][j]=tto[j];
45             }
46         }
47     }
48 }
49
50 int main(){
51     int u,v;
52     while(scanf("%d%d",&n,&s)!=EOF){
53         init();
54         for(int i=1;i<=n;i++)
55         scanf("%d",&num[i]);
56         for(int i=1;i<n;i++){
57             scanf("%d%d",&u,&v);
58             G[u].push_back(v);
59             G[v].push_back(u);
60         }
61         dfs(1,0);
62     //    int ans=max(dp_to[1][s],dp_back[1][s]);
63     //    ans+=num[1];
64         int ans=0;
65         for(int i=0;i<=s;i++)
66         ans=max(ans,max(dp_back[1][i],dp_to[1][i]));
67         printf("%d\n",ans);
68     }
69     return 0;
70 }

两个代码除了初始化的位置不一样,其他都是一样的。但我感觉代码2更符合本来的转移方程,你看一下初始化的位置就明白。但最终问题时,不能处理好,那就是当最大步数超过边数的两倍时问题,因为我在初始化时就认为这是一种不可能的情况了。。。

所以,请路过大牛给指点,以去掉最后的扫描一次得到结果。。。

POJ 2486

时间: 2024-12-27 13:07:52

POJ 2486的相关文章

POJ 2486 树形DP

有一颗苹果树,每个节点上面有很多苹果,从一个节点到另外一个可以到达的节点花费1步,求k步最多能吃到多少苹果,起始点为1,可以不回到起始点. 这是典型的回溯型树状dp. dp[i][j][0]代表以i为根节点的子树最多j步后回到i能吃到的最多的苹果, dp[i][j][1]代表以i为根节点的子树最多j步后不回到i节点最多能吃到的子树.那么状态转移就分三步了. (1)dp[i][j+2][0] = max(dp[i][j+2][0], dp[i][j-k][0]+dp[son][k][0]); (2

【POJ 2486】 Apple Tree(树型dp)

[POJ 2486] Apple Tree(树型dp) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8981   Accepted: 2990 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

【POJ 2486】 Apple Tree (树形DP)

Apple Tree 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 apples. Wshxzt starts her happy trip at one node. She can eat up all the apple

Apple Tree POJ - 2486

Apple Tree POJ - 2486 题目大意:一棵点带权有根树,根节点为1.从根节点出发,走k步,求能收集的最大权值和. 树形dp.复杂度可能是O(玄学),不会超过$O(nk^2)$.(反正这题不卡这个,考思想)参考 ans[i][j][0]表示i点以下共走j步,不回来,可能收集到最大的权值ans[i][j][1]表示i点以下共走j步,回来,可能收集到最大的权值 比较复杂的是,每个节点(以下称当前节点)从其子节点转移的时候,需要用一个背包: t[i][j][0]表示当前节点的前i个子节点

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

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 a apple tree

题意:n节点的树,从1开始走,总共v步,每个点都有一个价值,求可以获得的最大价值 分析:这个显然可以走回来,那么就加一维表示是否走回祖先 dp[u][i][j]表示从u为根节点的子树,往下走i步,j=0表示不走回来,j=1表示走回来 那么可以得到状态转移方程,不走回来的可能会影响走回来的,如果先算不会来的,那么一个节点在不走回来算一次 在走回来又算一次,所以先算走回来的就可以避免 dp[u][i][0]=max(dp[u][i][0],dp[u][i-j][1]+dp[v][j-1][0]);

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

题意:给定一棵树图,一个人从点s出发,只能走K步,每个点都有一定数量的苹果,要求收集尽量多的苹果,输出最多苹果数. 思路: 既然是树,而且有限制k步,那么树形DP正好. 考虑1个点的情况:(1)可能在本子树结束第k步(2)可能经过了j步之后,又回到本节点(第k步不在本子树) 第二种比较简单,背包一下,就是枚举给本节点的孩子t多少步,收集到最多苹果数.第一种的话要求第k步终止于本节点下的某个子树中,那么只能在1个孩子子树中,所以应该是[其他孩子全部得走回来]+[本孩子不要求走回来]   or