[题解] codevs 1486 愚蠢的矿工

http://codevs.cn/problem/1486/

我们比较熟悉二叉树,题目中给出的是一棵多叉树,我们需要将这可二叉树改造成二叉树。

二叉树可以为这样的:

父亲结点左边储存儿子,右边储存兄弟。

有两种改造方法:


if
(tree[x].l==0)tree[x].l=y; else { int k=tree[x].l; while(tree[k].r)k=tree[k].r; tree[k].r=y; }

tree[y].r = tree[x].l; tree[x].l = y;

之后再考虑转移,对于这个题来说,我们想要得到关于父节点的信息,就必须先处理完它的左右子树。

注意对于每个节点,这个节点可以不取而直接去取它的兄弟。

先处理每个节点的兄弟,在每个节点枚举向左可以放多少人,向右可以放多少人,更新过程递归实现。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n,m;
int a[1006],dp[1006][1006];
struct ahah{
    int l,r;
}tree[1006<<2];
int dfs(int k,int sum)
{
    if(!sum||!k)return 0;
    if(dp[k][sum]!=-1)return dp[k][sum];
    int ans=dfs(tree[k].r,sum);
    for(int i=0;i<sum;i++)
    {
        ans=max(ans,dfs(tree[k].l,i)+dfs(tree[k].r,sum-i-1)+a[k]);
    }
    dp[k][sum]=ans;
    return ans;
}
int main()
{
    memset(dp,-1,sizeof(dp));
    int x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        if(tree[x].l==0)tree[x].l=y;
        else
        {
            int k=tree[x].l;
            while(tree[k].r)k=tree[k].r;
            tree[k].r=y;
        }
    }
    printf("%d",dfs(tree[0].l,m));
}
原文地址:https://www.cnblogs.com/rmy020718/p/9592484.html