题目5--N盒点心

Problem Description
有N盒点心,这些盒子标号为1,2,…N,你有一次机会选择一些盒子作为你的晚餐,但是每个盒子里的点心的数量是未知的,不过有人告诉你一些信息:
①这些盒子里的点心总和是C个;
②对于盒子i,其中的点心个数最少的有low_i个,最多有high_i个,即low_i <= box_i <= high_i,box_i是第i盒的点心个数。
你选择的方式如下,一次挑出N盒中的若干盒,也就是{1,2,…N}的一个子集,然后拿走你选出的盒子,再打开它们,到此时你才知道你到底获得了多少个点心。为了吃饱晚餐,你需要吃X个点心,请问你至少需要选多少盒点心才能保证一定吃饱?
例如样例中:第一组选第3,4,5三盒第二组选第1,3两盒。
Input
多组测试数据,第一行一个整数T,表示测试数据数量,1 <= T <= 5
每组测试数据有相同的结构组成:
每组数据的第一行三个整数N,C,X,表示盒子个数、点心总数、需要的点心个数,其中1 <= N <= 50, 1 <= X <= C;
之后的N行,每行2个整数low_i,其中1 <= low_i <= high_i <= 10^7 ,同时保证SUM{low_i|1 <= i <= N} <= C <= SUM{high_i|1 <= i <= N},即数据确保点心总数与点心上下界的合法性;

Output
每组数据一行输出,即最少需要挑的盒子数量。
Sample Input
2
5 15 12
1 1
2 2
3 3
4 4
5 5
3 60 8
5 49
2 48
3 47
Sample Output
3
2
题目可以用贪心的方法解决,因为盒子里的点心数目不确定,只是一个大体的范围,因此为了保证一定吃饱,要考虑两个方面,一方面:下界要大于等于所需要的点心数。因为题目要求最少需要的盒子的数量,所以要把下界按照从大到小排列,排完后,从大的下界开始相加,直到数目大于等于所给的x即可。另一方面:需要x个,总共有c个,就是说有c-x个不选,因此不选的盒子里的点心的上界之和要小于等于c-x,(如果不选的上界之和大于了c-x,其余的再怎么选也不够了)这句话可以等价为c-不选的盒子里的点心的上界之和大于等于x,从总数n中逐个减去不选的,可以得到另一个数目。说明一下,在选择的时候为了保证吃饱,我们希望上界越大越好,但是不选择的盒子,上界越小越好,因此上界要从小到大排列。一方面按照下界我们可以得到一个数,按照下界我们也可以得到一个数,把这两个数比较,较小的那个数即为答案。

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int a;
    int b;

} s[51],p;
int main()
{
    int t,n,c,x,i,j,z;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n,&c,&x);
        for(i=0; i<n; i++)scanf("%d %d",&s[i].a,&s[i].b);
        for(i=1; i<n; i++)
        {
            for(j=0; j<=n-i-1; j++)
            {
                if(s[j].a<s[j+1].a)
                {
                    p=s[j];
                    s[j]=s[j+1];
                    s[j+1]=p;

                }

            }

        }



        int num1=0,num2=n;
        z=0;
        for(i=0; i<n; i++)
        {
            if(z<x)
            {
                z=z+s[i].a;
                num1++;

            }

        }

        for(i=1; i<n; i++)
        {
            for(j=0; j<=n-i-1; j++)
            {
                if(s[j].b>s[j+1].b)
                {
                    p=s[j];
                    s[j]=s[j+1];
                    s[j+1]=p;

                }

            }

        }


        for(i=0; i<n; i++)
        {
            if(c-s[i].b>=x)
            {
                c=c-s[i].b;
                num2--;


            }


        }

        if(num1<num2)
            printf("%d\n",num1);
        else printf("%d\n",num2);

    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值