POJ2486 树上背包裸题

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 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

这个题主要在于一个步数的分配问题…因此状态转移方程比较难理解….

给了K步,你不仅可以走入子树,还可以从子树中走出来。但是同一个节点只有第一次走过来的时候会得到他的权值。

其他的时候只能起到一个桥梁的作用。

在每一次的dfs中,每一个对应的子树都是独立的

因此其他的树所有的步数就都在 q-w中了

然后他的状态转移从高阶转移到低阶的原因是
他状态转移的和自己有关
如果他从小到大进行转移的话
那么
dp[gen][q + 2][0]
这一部分会不停地变大
有些类似于完全背包的那种

然而实际上不是..
这个树的每个节点只能够取一次
是01背包的思想

因此这个状态转移将从大到小来进行转移
便于和其他子树的状态进行比较

然后是状态转移方程
因为每个子树在对自己进行dfs的时候都是独特的
因此q-w已经把每颗子树的多余的东西算进去了

然后再看转移
对于这棵树,他的走路大概有这么几种可能
1.从树根走到叶子
2.从树根走到一棵子树的某个节点再走回去走到树根
再次从树根走出来
问题就在于这里
正常情况下一条路只能够走一次
而返回当作桥梁的情况就不是这样了
当他从当前子树走去其他子树的时候他每一步对于走入其他子树都是多余的。
dp[gen][q+2][0]是对于离开当前树去其他的树所采用的情况
dp[gen][q+2][1]和dp[gen][q+1][1]则是一种互相补充的状态转移

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
using namespace std;
int dp[101][301][2],n,k,biaoji[101],zhi[101];
vector<int> li[101];
void maxi(int &a, int b)
{
    if (a < b)a = b;
}
void dfs(int gen)
{
    biaoji[gen] = 1;
    for (int a = 0; a < li[gen].size(); a++)
    {
        if (biaoji[li[gen][a]] == 0)
        {
            dfs(li[gen][a]);
            for (int q = k; q >= 0; q--)
            {
                for (int w = 0; w <= q; w++)
                {
                    maxi(dp[gen][q + 2][0], dp[li[gen][a]][w][0]+dp[gen][q-w][0]);
                    maxi(dp[gen][q + 2][1], dp[li[gen][a]][w][0] + dp[gen][q - w][1]);
                    maxi(dp[gen][q + 1][1], dp[li[gen][a]][w][1] + dp[gen][q - w][0]);
                }
            }
        }
    }
}
int main()
{
    while (cin >> n >> k)
    {
        memset(dp, 0, sizeof(dp));
        memset(zhi, 0, sizeof(zhi));
        memset(biaoji, 0, sizeof(biaoji));
        for (int a = 1; a <= n; a++)
        {
            li[a].clear();
            cin >> zhi[a];
        }
        int q, w;
        for (int a = 1; a <= n - 1; a++)
        {
            cin >> q >> w;
            li[q].push_back(w);
            li[w].push_back(q);
        }
        for (int a = 1; a <= n; a++)
            for (int b = 0; b <= k; b++)
                dp[a][b][0] = dp[a][b][1] = zhi[a];
        dfs(1);
        cout << max(dp[1][k][1], dp[1][k][0]) << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值