poj2709

11 篇文章 0 订阅

贪心水题。题意大致为:给定要制作的颜色个数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;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值