mltang

博客园 首页 新随笔 联系 订阅 管理

这题主要是树形dp

思路就是01背包,小细节都写在代码里了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
const int maxn = 2e2+5;
int n,m;
vector<int> tree[maxn];
int dp[maxn][maxn];
bool vis[maxn];
void dfs(int u);
int main()
{
    int i,j,k,a,b;
    while(scanf("%d%d",&n,&m) && (n||m))
    {
        m++;
        //因为有个0节点  所以一共要考虑m+1个点  0节点的价值为0
        memset(dp, 0, sizeof(dp));
        for(i=0;i<=n;++i)
        {
            tree[i].clear();
        }
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&a,&b);
            dp[i][0] = 0;
            dp[i][1] = b;
            tree[a].push_back(i);
        }
        dfs(0);
        printf("%d\n",dp[0][m]);
    }
}
void dfs(int u)
{
    int i,j,k;
    for(i=0;i<tree[u].size();++i)
    {
        int t=tree[u][i];
        if(tree[t].size())
            dfs(t);
        for(j=m;j>=2;--j)
        {
            for(k=1;k<j;++k)
            {
                /*
                 这个地方我当时想了一个问题
                    1
                 2     3
              4     7  6  8 10
            9          11
                 假设我现在要求dp[3][4]
                 假设3点价值3  7点价值1  6点价值2  8点价值1  10点价值1  11点价值2
                 
                 dp[3][4] = max(dp[3][4],dp[3][2]+dp[6][2]);
                 那么问题来了
                 dp[3][2]的最大价值是5  dp[6][2]的价值是4
                 但是6这个点被取了两次,我怎么才能保证6不被取两次呢
                 其实这个也不难想,画一遍也就明白了
                 
                 现在到达3节点,7子节点没有儿子,这时候只有3、7节点被考虑了
                 接下6节点有儿子,进入后,经过一系列操作求出dp[6][1..m]
                 这时候才3、6、7被考虑到
                 所以说不存在6被多次取到的情况
                 */
                dp[u][j]=max(dp[u][j],dp[u][k]+dp[t][j-k]);
            }
        }
    }
}

 

posted on 2018-04-20 13:06  mltang  阅读(98)  评论(0编辑  收藏  举报