二分查找之求最大值的最小值 洛谷P1182

题目链接:点击这里

看到题目中的“最大值最小”就知道这题主要考察的是用二分法求满足条件的最小值

所以关于mid的求法如下:

	while(l < r)
	{
		mid = (l + r)/2;//注意是(l+r)
		if(judge(mid))//符合条件
			r = mid;
		else
			l = mid + 1;
	}

其中的

mid = (l + r)/2;

若要防止溢出可写成

mid = l + (r-l)/2;

详情请见大佬的博客

关于"L"和"R"的选取:

每段和的最大值的最小的情况就是把每个数当做单独的一段其中最大的一个,每段和的最大值的最大的情况就是把所有的数当成一段,即所有数的和

接下来就是"judge"这个函数该怎么写:

我的想法是用一个变量来计数,统计以当前mid作为每一段和的最大值时会划分出多少段,如果统计出的数量小于等于规定的段数,说明当前的mid是可行的,但未必是最小的,所以接着二分。代码如下:

bool judge(int x)//传入mid
{
	int num = 0,sum = 0;
	int i;
	for(i = 1;i <= N;i++)
	{
		sum += a[i];
		if(sum > x)//当前累加的和大于mid,说明到a[i]的前一个为止是一段
		{
			i --;//回溯一个,下一步循环从当前的a[i]开始累加
			num ++;//统计段数
			sum = 0;//重新开始计数
		}
		
	}
	if(sum)//注意:最后一段的累加值若小于等于mid在上面的循环中不会计数,这里加上
		num++;
	return num <= M;
}

最后,附上全部代码:

#include "stdio.h"
#define Max 100002
int N,M,a[Max];

bool judge(int x)
{
	int num = 0,sum = 0;
	int i;
	for(i = 1;i <= N;i++)
	{
		sum += a[i];
		if(sum > x)
		{
			i --;
			num ++;
			sum = 0;
		}
		
	}
	if(sum)
		num++;
	
	return num <= M;
}

int main()
{
	scanf("%d%d",&N,&M);
	int i,max=0,sum=0;
	for(i = 1;i <= N;i++)
	{
		scanf("%d",&a[i]);
		sum += a[i];
		if(a[i] > max)
			max = a[i];
	}
	int l,r,mid;
	l = max;
	r = sum;
	while(l < r)
	{
		mid = (l + r)/2;
		if(judge(mid))
			r = mid;
		else
			l = mid + 1;
	}
	
	printf("%d",r);
	
	return 0;
}

 

你可能感兴趣的:(二分查找之求最大值的最小值 洛谷P1182)