zoukankan      html  css  js  c++  java
  • E

    E - Apple Tree POJ - 2486 

    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 apples in the nodes she reaches. HX is a kind guy. He knows that eating too many can make the lovely girl become fat. So he doesn’t allow Wshxzt to go more than K steps in the tree. It costs one step when she goes from one node to another adjacent node. Wshxzt likes apple very much. So she wants to eat as many as she can. Can you tell how many apples she can eat in at most K steps.

    Input

    There are several test cases in the input
    Each test case contains three parts.
    The first part is two numbers N K, whose meanings we have talked about just now. We denote the nodes by 1 2 ... N. Since it is a tree, each node can reach any other in only one route. (1<=N<=100, 0<=K<=200)
    The second part contains N integers (All integers are nonnegative and not bigger than 1000). The ith number is the amount of apples in Node i.
    The third part contains N-1 line. There are two numbers A,B in each line, meaning that Node A and Node B are adjacent.
    Input will be ended by the end of file.

    Note: Wshxzt starts at Node 1.

    Output

    For each test case, output the maximal numbers of apples Wshxzt can eat at a line.

    Sample Input

    2 1 
    0 11
    1 2
    3 2
    0 1 2
    1 2
    1 3
    

    Sample Output

    11
    2
    题意:给你一棵以1为根节点的树,树上的每个节点有arr[i]苹果,从1出发最多能走k步,问最多能得到多少个苹果。
    题解:一开始没有思考到能还能走回来的的情况,就以为是一道广搜就可以了,然后听别人说才知道是一个树形dp
    起点已经确定为1,那么取得最大值仅有两种情况,一种是走了k步之后,回到1了,另一种是走了k步,终点没回到1,停在某一个子节点上。
    那么对于每一个节点的最大值都可以这样认为,每个节点的最大值都是走K步,回到起点/不回到起点。
    定义三位数组dp[i][j][k] , i 为起点 , j 为走的步数 , k = 0 表示不回到起点 ,k = 1 表示回到起点。
    每个父亲节点的值,都可以由他的子节点来更新
    对于状态转移方程
    dp[i][j][1] = max(dp[i][j][1] , dp[i][j - m][1] + dp[v][m - 2][1]);
    最终都要返回起点i,dp[v][m - 2][1] 代表从i的其中一个子节点v传递上拉来的走 m - 2步的获取苹果的最大值,之所以是m-2步,因为 i 和 v 之间的往返消耗了两步
    dp[i][j][0] = max(dp[i][j][0] , max(dp[i][j - m][1] + dp[v][m - 2][0] , dp[i][j - m][0] + dp[v][m - 2][1]));
    最终不返回起点i ,其终点有可能停留在子节点v所在的子树中,也有可能从v节点的子树中返回,停留在另一个子树中。
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<vector>
     7 #include<queue>
     8 #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
     9 #define mem(a,x) memset(a,x,sizeof(a))
    10 #define lson rt<<1,l,mid
    11 #define rson rt<<1|1,mid + 1,r
    12 #define P pair<ll,ll>
    13 #define ull unsigned long long
    14 using namespace std;
    15 typedef long long ll;
    16 const int maxn = 1e5 + 10;
    17 const ll mod = 1e9 + 7;
    18 const int inf = 0x3f3f3f3f;
    19 const long long INF = 0x3f3f3f3f3f3f3f3f; 
    20 int k, n, T, m, t;
    21 vector<int>edge[500];
    22 int arr[500];
    23 int dp[500][500][2]; // 三维 1 表示返回出发点 , 0 表示不返回出发点
    24 void dfs(int u, int start)
    25 {
    26     for (int i = 0; i < edge[u].size(); ++i)
    27     {
    28         int v = edge[u][i];
    29         if (v == start) continue;
    30         dfs(v, u);
    31         for (int j = k; j >= 1; --j)
    32         {
    33             for (int m = 1; m <= j; ++m)
    34             {
    35                 if(m == 1)
    36                     dp[u][j][0] = max(dp[u][j][0], dp[u][j - m][1] + dp[v][m - 1][0]);
    37                     //从起点u出发走j步,不返回u的最大值,
    38                 else
    39                 {
    40                     dp[u][j][0] = max(dp[u][j][0], max(dp[u][j - m][1] + dp[v][m - 1][0] , dp[u][j - m][0] + dp[v][m - 2][1]));
    41                     dp[u][j][1] = max(dp[u][j][1], dp[u][j - m][1] + dp[v][m - 2][1]);
    42                 }
    43             }
    44         }
    45 
    46     }
    47 }
    48 
    49 
    50 
    51 int main()
    52 {
    53     while (scanf("%d %d", &n, &k) != EOF)
    54     {
    55         for (int i = 1; i <= n; ++i)
    56                 edge[i].clear();
    57         mem(dp, 0);
    58         mem(arr, 0);
    59         for (int i = 1; i <= n; ++i)
    60             scanf("%d", &arr[i]);
    61         for (int i = 1; i <= n; ++i)
    62             for (int j = 0; j <= k; ++j)
    63                 dp[i][j][0] = dp[i][j][1] = arr[i];
    64         for (int i = 1; i < n; ++i)
    65         {
    66             int u, v;
    67             scanf("%d %d", &u, &v);
    68             edge[u].push_back(v);
    69             edge[v].push_back(u);
    70         }
    71         dfs(1, -1);//建立一个根节点
    72         printf("%d
    ", max(dp[1][k][1], dp[1][k][0]));
    73         
    74     }
    75     return 0;
    76 }
    AC代码

    一个从很久以前就开始做的梦。







  • 相关阅读:
    C#里边的控件缩写大全(比较规范)
    jQuery的一些备忘
    有趣的史实~
    值类型 VS 引用类型~
    一道笔试题和UML思想 ~
    数据绑定以及Container.DataItem几种方式与用法分析
    用户控件与自定义控件的异同
    .NET资源站点汇总~
    C#中抽象类和接口的区别
    弹出窗口的一些东西(一),备忘~
  • 原文地址:https://www.cnblogs.com/DreamACMer/p/11739622.html
Copyright © 2011-2022 走看看