派遣忍者

题目描述 Description

  在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。
  在这个帮派里,有一名忍者被称之为Master。除了Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。
  现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被派遣,你就不需要支付管理者的薪水。
  你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力,其中每个忍者的领导力也是一定的。
  写一个程序,给定每一个忍者i的上级Bi,薪水Ci,领导力Li,以及支付给忍者们的薪水总预算M,输出在预算内满足上述要求时顾客满意度的最大值。

输入描述 Input Description

  第一行包含两个整数N和M,其中N表示忍者的个数,M表示薪水的总预算。
  接下来N行描述忍者们的上级、薪水以及领导力。其中的第i行包含三个整数B, C, Li分别表示第i个忍者的上级,薪水以及领导力。Master满足Bi= 0,并且每一个忍者的上级的编号一定小于自己的编号 Bi < i。

输出描述 Output Description

  输出一个数,表示在预算内顾客的满意度的最大值。

样例输入 Sample Input

      5 4
      0 3 3
      1 3 5
      2 2 2
      1 2 4
      2 3 1

样例输出 Sample Output

      6

数据范围及提示 Data Size & Hint

   【样例解释】

  如果我们选择编号为1的忍者作为管理者并且派遣编号为3和编号为4的忍者,薪水总和为4,没有超过总预算4。因为派遣了2个忍者并且管理者的领导力为3,用户的满意度为2 × 3 = 6,是可以得到的用户满意度的最大值。

   【数据规模】

  1 ≤ N ≤ 100,000 忍者的个数;
  1 ≤ M ≤ 1,000,000,000 薪水总预算;
  0 ≤ Bi < i 忍者的上级的编号;
  1 ≤ Ci ≤ M 忍者的薪水;
  1 ≤ Li ≤ 1,000,000,000 忍者的领导力。

  对于30%的数据,N ≤ 3000。

解题思路:声明两个数组person和num,person用来存储忍者上级,领导力,雇佣该忍者时剩余的金钱数和该忍者为管理者时可以拥有的最多属下的数目;num用来存储忍者的序号和雇佣该忍者需花费金额。先对num数组根据雇佣每名忍者需花费金额排序,得到新的num数组根据金钱从小到大排序。然后遍历num数组,寻找每位忍者的领导,并雇佣当前忍者,扣除所需金额,并记录在person数组中。最后进行比较,选出最佳方案。思路属于暴力破解。

#include <stdio.h>
#define M 100001
#define MAX(a,b) a>b?a:b
void swap(long long *a,long long *b);
void sort(long long (*num)[2],long long begin,long long end);
int main(void)
{
	long long N=0,Mon=0;
	long long person[M][4]={0},i=0,j=0,num[M][2]={0};
	int father=0,money=0;
	scanf("%lld %lld",&N,&Mon);
        //接收数据
        for(i=1;i<=N;i++)
	{
		num[i][0] = i;
		scanf("%lld %lld %lld",*(person+i)+0,*(num+i)+1,*(person+i)+1);
		person[i][2] = Mon;
	}
        //排序
        sort(num,1,N);
        //遍历num数组中的成员,寻找每位忍者的最终上司,并记录过程
        for(i=1;i<=N;i++)
	{
		father = num[i][0];
		money = num[i][1];
                        //寻找上司,并记录下过程中雇佣人员的增加,金额的变化
                        while(father!=0&&person[father][2]>=money){
			person[father][2]-=money;
			person[father][3]++;
			father = person[father][0];
		}
	}
        //遍历person数组,比较出最大的满意度
        long long ans=0;
	for(i=1;i<=N;i++)
	{
		ans = MAX(ans,person[i][1]*person[i][3]);
	}
	printf("%lld\n",ans);
	return 0;
}
//交换num数组中的两个元素
void swap(long long *a,long long *b)
{
	long long tmp = a[0];
	a[0] = b[0];
	b[0] = tmp;
	tmp = a[1];
	a[1] = b[1];
	b[1] = tmp;
}
//对num数组排序
void sort(long long (*num)[2],long long begin,long long end)
{
	long long i=0,j=0;
	if(begin<end)
	{
		i = begin+1;
		j = end;
		while(i<j)
		{
			if(num[begin][1]<num[i][1])
			{
				swap(*(num+i),*(num+j));
				j--;
			}
			else i++;
		}
		if(num[begin][1]<=num[i][1]) i--;
		swap(*(num+begin),*(num+i));
		sort(num,begin,i);
		sort(num,j,end);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要出家当道士

打赏是不可能,这辈子都不可能

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值