Vijos P1418 公司聚会

公司聚会

Description

dd_engi所在的TIANYI公司要举办一次盛大的公司聚会。可惜的是,由于场地和花费的原因,不可能所有人都参加。现在的任务是拟定参加聚会人员的名单。

TIANYI公司的组织架构可以看做一棵有根多叉树。也就是说,在编号为1~N的所有N名员工中,除了最高管理者(编号为1)以外,每个员工都有且仅有一位直接上司;最高管理者则是这棵多叉树的“根”。这很好理解,对吗?另外,我们保证,员工的编号会大于他的直接上司的编号。

不同的员工对于聚会有着不同的要求,事实上,若邀请第i位员工(编号为i),在聚会中满足他的要求需要花费Ci元。另一方面,不同的员工在聚会中的“兴奋指数”也不同,第i位员工参加聚会的兴奋指数是Ei。

选择参加聚会的人员还有一个限制:为了使参加聚会的员工能够尽量放松,若邀请了某位员工,就不能邀请他的任何一位上司。这里“上司”的定义是这样的:最高管理者没有上司,其余所有员工的直接上司以及直接上司的所有上司都是他的上司。换句话说,某位员工的上司就是树中从他的节点走到根节点的路径上经过的所有节点(包括根结点,但不包括他自身)。

在满足上述限制的前提下,dd_engi希望参加聚会人员的兴奋指数之和最大,但同时他被告知,满足所有参加聚会人员的要求的总花费不得超过M元。那么,参加聚会人员的名单究竟应该怎样确定才最优呢?你需要求出的是最大的总兴奋指数。

Input

第一行,两个空格隔开的整数,N与M。

第二行,N-1个整数,分别是第2位至第N位员工的直接上司的编号。

第三行,N个整数,分别是C1、C2……CN。

第四行,N个整数,分别是E1、E2……EN。

Output

只需输出一行一个整数,即最大的总兴奋指数。

Sample Input

10 100
1 2 2 1 4 3 5 6 1
12 53 127 32 164 22 199 10 19 17
-1 0 3 5 7 -2 9 6 8 13

Sample Output

27

Answer

/**
感觉这个题迷迷糊糊就写过了
dp[i][j]代表以i为根节点的子树上面花费j元所能得到的最大的兴奋值
那么i从1~n,当i一定时,要么只邀请根节点,要么邀请他的子树们
邀请根节点的很好写,
邀请子树的,就成了有1~vec[i].size()件物品,花费为j能达到的最大值的01背包
那么对于每一个子树,他的花费v需要从0到m枚举,对应的值为dp[p][v];
具体见代码
**/
#include 
   
   
    
    
#define maxn (10000 + 10)
using namespace std;

vector
    
    
     
      Vec[maxn];

struct Node {
    int c;
    int e;
} op[maxn];

int dp[maxn][maxn];

int main() {
//    freopen("in.txt","r",stdin);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 2; i <= n; i ++) {
        int pre;
        scanf("%d",&pre);
        Vec[pre].push_back(i);
    }
    for(int i = 1; i <= n; i ++)  scanf("%d",&op[i].c);
    for(int i = 1; i <= n; i ++)  scanf("%d",&op[i].e);
    for(int i = n; i >= 1; i --) {
        for(int k = 0; k < Vec[i].size(); k ++) {
            int p = Vec[i][k];
            for(int j = m; j >= 0; j --) {
                for(int v = 0; v <= j; v ++){
                    if(dp[p][v] == 0)   continue;
                    dp[i][j] = max(dp[i][j],dp[i][j - v] + dp[p][v]);
                }
            }
        }
        for(int j = m; j >= op[i].c; j --)
            if(dp[i][j] < op[i].e)    dp[i][j] = op[i].e;
    }
    printf("%d\n",dp[1][m]);
    return 0;
}
    
    
   
   


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值