贪心水题。题意大致为:给定要制作的颜色个数n,和这n个颜色分别对应的容量,以及要制作的灰色容量。问至少用多少袋含n种颜色各50ML?
这里灰色没有直接的颜色提供。灰色的制作方法为:任意不同的三种颜色分别为容量xML,则混合后为容量xML灰色。那么题意已经很明确了。
分析如下:可以分两步绘制所有的颜色
1)首先绘制不是灰色的颜色。这样的化至少需要max(各颜色中(除开灰色)所需的容量最大值)/ 50 (max整除50),或者 max/50+1 (max没有整除50)袋
2)在保证满足除开灰色所需颜色均可以提供的情况下,再来考虑制作灰色的情况。由题意可知制作灰色的原料应该是在提供了除开灰色各颜色所需容量均满足的条件下,从多余的颜色中选择组合来制作灰色。这样的化,就可以限定最大袋数和最小袋数。而且由于绘制灰色容量随着袋数的增加而增加,即满足单调递增性质,故可以采用二分法减少枚举范围。而判断每种袋数情况下灰色最多制作量 是大于灰色容量,还是正好等于灰色容量,或者小于灰色容量则采用贪心算法。整个算法的时间复杂度近似为0(num*n)。
贪心准则为:每次都从各种颜色中选取最多的三中颜色,然后组成一ML的灰色,不断重复,直至无法组成灰色后组成灰色容量大于要求的灰色容量
下面是代码:164K+0MS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 20
int init[Max];
int record[Max];
int n,num;
int Binary_search(int number){
for(int i=1;i<=n;i++)
record[i]=number*50-init[i];
int Sum=0;
int first,second,third;
int fmax,smax,tmax;
bool trag;
while(Sum<=num){
fmax=-1,smax=-1,tmax=-1;
trag=true;
for(int i=1;i<=n;i++)
if(record[i]>0 && record[i]>fmax){
fmax=record[i];
first=i;
}
for(int i=1;i<=n;i++)
if(record[i]>0 && record[i]>smax && i!=first){
smax=record[i];
second=i;
}
for(int i=1;i<=n;i++)
if(record[i]>0 && record[i]>tmax && i!=first && i!=second){
trag=false;
tmax=record[i];
third=i;
}
if(trag)
break;
Sum++;
record[first]--,record[second]--,record[third]--;
}
if(Sum<num)
return -1;
else if(Sum==num)
return 0;
else
return 1;
}
int main(){
while(scanf("%d",&n),n){
int max_v=-1;
for(int i=1;i<=n;i++){
scanf("%d",&init[i]);
if(init[i]>max_v)
max_v=init[i];
}
scanf("%d",&num);
if(max_v==0 && num==0){
printf("0\n");
continue;
}
else{
int left,right,mid;
if(max_v%50==0){
left=max_v/50;
right=left+num/50+1;
}
else{
left=max_v/50+1;
right=left+num/50+1;
}
bool flag=false;
while(left<=right){
mid=(left+right)>>1;
if(Binary_search(mid)==-1)
left=mid+1;
else if(Binary_search(mid)==0){
flag=true;
break;
}
else
right=mid-1;
}
if(flag)
printf("%d\n",mid);
else
printf("%d\n",left);
}
}
return 0;
}