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;
}