poj3273 Monthly Expense(花销)-二分查找

题意描述

给定n天的花销,把花销分成连续的m份,使得每一段时间花销和的最大值最小。

样例输入

7 5
100
400
300
100
500
101
400

样例输出

500

思路

设每天花销为expense[i] (0<=i<n),每段时间花销为cost[j] (0 <= j < m)

答案有一个区间:max(expense[i])<=answer<=max(cost[i])

设为[l,r]

在这个区间进行二分确定中值mid,然后看这样分组能不能恰好分出m份。如果分出m份多,说明mid太小了,舍去前半段。在后半段继续二分。反之舍去后半段在前半段二分,直到l = r,此时的mid就是答案了。需要注意的是,满足分成m份的mid可能有多个,因在恰好等于m份时缩小边界的方向是向mid更小的方向才正确,举例,当mid = 5时m = 3,当mid = 3时 m = 3,因为mid缩小的范围是向l,使得能得出正确答案answer = 3而非5。

代码

#include <bits/stdc++.h>
using namespace std;
int expense[100010];//数组存每日开销 
int main(){
	int n,m,l = 0,r = 0;//l和r分别为二分查找的左右界 l为单日最大值 r为总值 
	scanf("%d %d",&n,&m);
	for(int i = 0;i < n;i++){
		scanf("%d",&expense[i]);
		if(expense[i] > l)l = expense[i];
		r += expense[i];
	}
	int mid;//二分变量 
	do{
		mid = (l+r)/2; 
		int x = 0,now = 0;//x代表有多少组,now代表当前组开销 
		for(int i = 0;i < n;i++){
			if(now + expense[i] > mid)
			x++,now = expense[i];
			else
			now += expense[i];
		}
		x++;//最后的一组没有超过mid不通过上面增加x,在这里单独加上。 
		if(x > m)l = mid+1;//大于所给的天数 
		else r = mid-1;
	}while(l <= r);
	printf("%d\n",mid);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/krypton12138/article/details/80189192