洛谷P2440 二分边界点分析

洛谷p2440 木材加工

题目描述
木材厂有 n根原木,现在想把这些木头切割成 k 段长度均为L的小段木头(木头有可能有剩余)。
当然,我们希望得到的小段木头越长越好,请求出 L 的最大值。
木头长度的单位是cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。
例如有两根原木长度分别为 1111 和 2121,要求切割成等长的 66 段,很明显能切割出来的小段木头长度最长为 55。

今天水一篇文章,刚刚刷到这道题的时候,还在想他和二分啥关系,后来终于想清楚了,用来木材切割的最大长度不就是木材的总长去除以所需要的段数嘛,不过一般不可能这么巧的啦,通常要比这个最大的长度小,那么如何快速找到这个最适长度呢,那就是要对0~max这个区间进行二分查找了,我的二分查找如下:

bool check(int sum)   //用来判断这个长度合不合适
{
    
    
	int ans=0;
	for(int i=0;i<n;i++)
	{
    
    
		ans+=p[i]/sum;
	}
	if(ans>=l)
	{
    
    
		return true;
	}
	else
	return false;
}
void dp(int l,int r)
{
    
    
	while(l<r)
	{
    
    
		int mid=(l+r+1)/2;
		if(check(mid)) l=mid;
		else r=mid-1;	
	}
	cout<<r<<endl;
}

看到二分查找,就有最让人头疼的问题,这个边界怎么取啊?取偏左还是偏右的中间点啊…
我们可以这么想,假如,现在有两个数字,左边那个是合适的,而右边那个是不合适的,假如我们取偏左边的中间点,可以想象到待会那个check就会返回true,会发生什么?没错,那就是L边界右移了,可是刚刚已经说过,那个右边是不合适的,偏偏这个时候L和R就重叠在一起,就跳出循环,那么必定得到错误的结果;反过来,如果你取偏右的中间点,那么待会R就会回退,不信的话手动模拟一下。所以,我们需要取偏右的那个中间点,所以mid就要+1的意思
最后,附上AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
int p[100009];
int n,l;
bool check(int sum)
{
    
    
	int ans=0;
	for(int i=0;i<n;i++)
	{
    
    
		ans+=p[i]/sum;
	}
	if(ans>=l)
	{
    
    
		return true;
	}
	else
	return false;
}
void dp(int l,int r)
{
    
    
	while(l<r)
	{
    
    
		int mid=(l+r+1)/2;
		if(check(mid)) l=mid;
		else r=mid-1;	
	}
	cout<<r<<endl;
}
int main()
{
    
    
	cin>>n>>l;
	unsigned long long s=0;
	for(int i=0;i<n;i++)
	{
    
    
		cin>>p[i];
		s+=p[i];
	}
	dp(0,s/l);
} 

猜你喜欢

转载自blog.csdn.net/weixin_51295863/article/details/127181030
今日推荐