poj3273.Monthly Expense(二分答案最大值最小化问题)

题意:对给给出的n个数,划分为m块,使每一块中所有数的和的最大值最小,是经典的最大值最小问题。

一些思考:

用到二分我也觉得一开始没想到,现在觉得确实用二分挺合理的
1.即首先求出二分的上下限,这个是每次二分必做的准备工作, 上限即为这一堆东西的总量,下限即单个最大的物品的值。
2.有上下限之后即开始二分,最难写的部分就出来了,即判断当前分堆是否合理,在判断分堆是否合理中,主要的限制因素为两个,一个是单堆的量肯定不能超过当前的Mid值,另一个是分出的堆数一定不能超过题目要求的M值
3.由判断条件即可将二分范围进行缩小,即,一旦当前Mid值满足分堆要求,意味着我还可以把Mid值缩小,即把二分的right=mid,如果当前Mid值触犯了判断条件,即说明当前值还太小,即把left=mid。
4.由以上二分return出来的结果即为所求值


代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100006;
int a[maxn];
int n;
int judge(int x){
 int now=0;
 int cnt=1;
 for(int i=0;i<n;i++){
  if(now+a[i]>x){
   cnt++;
   now=a[i];
  }else{
   now+=a[i];
  }
 }
 return cnt;
}
int main(){
 int m,l=0;
 int sum=0;
 scanf("%d%d",&n,&m);
 for(int i=0;i<n;i++){
  scanf("%d",&a[i]);
  l=max(l,a[i]);
  sum+=a[i];
 }
 int r=sum;
 int mid;
 while(l<r){
  mid=(l+r)/2;
  int num=judge(mid);
  if(num<=m){
   r=mid;
  }else{
   l=mid+1;
  }
 }
 printf("%d\n", r);
}

猜你喜欢

转载自blog.csdn.net/running_acmer/article/details/80503681