NYOJ 摘枇杷 (最大化最小值)

题目链接:http://115.159.40.116/problem_show.php?pid=5264


题目描述

理工学院的枇杷快熟了,ok,大家都懂得。而且大家都知道,学校的枇杷树都是一列一列的。现在小Y同学已经在筹划怎么摘枇杷了。现在我们假设有一列枇杷树,而且每棵枇杷树上枇杷果的数量小Y都已经知道了。

假设现在有n棵枇杷树,小Y可以把这n棵枇杷树分成m组,每组枇杷果的数量是这组内每棵枇杷树上枇杷果数量的和。注意,每组的枇杷树必须是连续的。(每组最少1棵树,最多n棵树)。小Y把枇杷往寝室拿的时候是一组一组拿的,所花费的力气等于这m组中枇杷果最多的那组枇杷果的数量。现在小Y想花尽量少的力气把这些枇杷果拿回寝室。

输入

多组测试数据,以EOF结束(<= 100组)
每组测试数据第一行有两个数n(n <= 1000)和m(1 <=m <= n)
第二行有n个数,分别代表每颗树上枇杷果的数量

输出

输出小Y同学所花费的最小的力气,每个结果占一行。

样例输入

3 2
1 2 3
7 5
1 4 3 1 5 2 4

样例输出

3
5


解释:

把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值最小是多少?
例子: 
序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,那么最大值为7; 
如果划分为 1 2 | 3 2 | 5 4,则最大值为9,不是最小。

我们对问题做一些转化: 
在一次划分中,求一个x,使得x满足:对任意的S(i),都有S(i)<=x;这个条件保证了x是所有S(i)中的最大值。我们需要求的就是满足该条件的最小的x。
有了这个思路之后,我们继续分析如何找到这个x,首先,可以知道的是,max <= x <= sum。
接下来先是最朴素的想法:枚举每一个x,贪心地每次从左向右尽量多划分元素,但是S(i)不能超过x,而且划分的子序列个数不能超过m个(即所用划分线不能超过m-1条)
以上方法当然可行,但是每个x都遍历一次太浪费时间了。
问题经过转化,现在变成了在[max, sum]中间查找一个满足条件的x,查找的问题,相信大家对二分搜索并不陌生。这个时候,用二分搜索的思想来求x,效率一下子就上来了。


题目代码:


#include<iostream>
#include<cstdio>
#define M 1000+5
using namespace std;

int a[M],n,m,mmax,sum;

bool is_part(int mid){
	int line=0,i,s=0;
	for(i=0; i<n; ++i){
		//if(a[i]>mid) return false;
		if(s+a[i]>mid){
			line++;
			s=a[i];
			if(line>m-1) return false;
		}else s+=a[i];
	}
	return true;
}

int bi_search(){
	int l=mmax,r=sum;
	while(l<=r){
		int mid=(r+l)/2;
		if(is_part(mid)) r=mid-1; 
		else l=mid+1;
	}
	return l;
}

int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		sum=0,mmax=0;
		for(int i=0; i<n; ++i){
			scanf("%d",&a[i]);
			sum+=a[i];
			mmax=max(mmax,a[i]);
		}
		printf("%d\n",bi_search());	
	}
	return 0;
}


资料链接:http://www.lai18.com/content/938413.html

资料链接:http://blog.csdn.net/lyhvoyage/article/details/23263275

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值