zoukankan      html  css  js  c++  java
  • codevs1486愚蠢的矿工(树形dp)

    1486 愚蠢的矿工

     

     时间限制: 1 s
     空间限制: 128000 KB
     
     
    题目描述 Description

    Stupid 家族得知在HYC家的后花园里的中央花坛处,向北走3步,向西走3步,再向北走3步,向东走3步,再向北走6步,向东走3步,向南走12步,再向西走2步( - -||)就能找到宝藏的入口,而且宝藏都是藏在山里的,必须挖出来,于是Stupid家族派狗狗带领矿工队去挖宝藏.(HYC家的宝藏被狗狗挖走后有什么感想?)

    这个宝藏的制造者为了掩盖世人耳目,他做的宝藏是没有出口,只有入口,不少建造宝藏的人都死在里面.现在知道宝藏总共有N个分岔口,在分岔口处是有财宝的,每个宝藏点都有一个财富值.狗狗只带了M个人来,而且为了安全起见,在每个分岔口,必须至少留一个人下来,这个留下来的人可以挖宝藏(每个人只能挖一个地方的宝藏),这样才能保证不会迷路,而且这个迷宫有个特点,任意两点间有且只有一条路可通.狗狗为了让他的00开心,决定要尽可能地多挖些宝藏回去.现在狗狗的圈叉电脑不在身旁,只能求救于你了,你要知道,狗狗的终身幸福就在你手上了..(狗狗ps:00,你不能就这样抛弃偶……)

    数据范围

    对于10%的数据,n<10

    对于100%的数据,n<=1000

    输入描述 Input Description

    第1行:两个正整数N,M .N表示宝藏点的个数,M表示狗狗带去的人数(那是一条懒狗,他自己可不做事)。(m<=100)

    第2行:N个整数,第i个整数表示第i个宝藏的财富值.(保证|wi|<maxint)

    第N+2行:两个非负整数A和B,表示A通向B,当A=0,表示A是入口.(保证A,B<=n)

    输出描述 Output Description

    输出狗狗能带回去的宝藏的价值。

    样例输入 Sample Input

    4 3

    5 6 2 4

    1 2

    0 1

    2 3

    3 4

    样例输出 Sample Output

    13

    /*
    树形DP f[i][j]表示当前节点为i,还剩j个人能获得的最大价值。 
    多叉树转二叉树,左儿子右兄弟 
    所以不能只选左孩子,但可以不选当前节点,只选右孩子 
    转化好了之后就是DP了。 
    写的记忆化 递归每个节点 枚举分给左右孩子的人数  
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1010
    
    using namespace std;
    int n,m,ans,x,y;
    int f[maxn][maxn],a[maxn],son[maxn][3];
    
    int DP(int root,int cnt)
    {
        int maxx=0;
        if(f[root][cnt])return f[root][cnt];//记忆化 
        if(root==0||cnt==0)return 0;//剪枝 
        f[root][cnt]=a[root];//选择当前节点 
        for(int i=1;i<=cnt;i++)
        {
            if(DP(son[root][1],i-1)+a[root]+DP(son[root][2],cnt-i)>maxx)
              maxx=DP(son[root][1],i-1)+a[root]+DP(son[root][2],cnt-i);//左孩子分配i个人,并且选择这个节点。 
            if(DP(son[root][2],i)>maxx)
              maxx=DP(son[root][2],cnt);//不选当前节点,只选右孩子(他的兄弟节点).
        }
        if(f[root][cnt]<maxx) f[root][cnt]=maxx;
        return f[root][cnt];
    }
    
    int main()
    {
        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(son[x][1]==0)son[x][1]=y;//1是左孩子,2是右孩子 
            else
            {
                int fa=son[x][1];
                while(son[fa][2])fa=son[fa][2];
                son[fa][2]=y;
            }
        }
        ans=DP(son[0][1],m);
        printf("%d
    ",ans);
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    VS2019删除大量空白行或者缩进大量空白行
    VS219 没有.net core 3.0模板
    Win10怎么添加开机启动项?Win10添加开机自动运行软件三种方法
    Unity 屏幕坐标到UGUI RectTransform本地坐标的转换
    MySQL 常用帮助信息
    CentOS 7 系统初始化
    JDK 安装部署
    centos7 yum install redis
    Redis5.0.3单机版安装
    shell 脚本检测端口状态
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6361246.html
Copyright © 2011-2022 走看看