P2440 木材加工 ---初见二分法

题目背景

要保护环境

题目描述

木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头(木头有可能有剩余),需要得到的小段的数目是给定的。当然,我们希望得到的小段木头越长越好,你的任务是计算能够得到的小段木头的最大长度。木头长度的单位是cm。原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

例如有两根原木长度分别为11和21,要求切割成到等长的6段,很明显能切割出来的小段木头长度最长为5.

输入格式

第一行是两个正整数N和K(1 ≤ N ≤ 100000,1 ≤ K ≤ 100000000),N是原木的数目,K是需要得到的小段的数目。

接下来的N行,每行有一个1到100000000之间的正整数,表示一根原木的长度。

输出格式

能够切割得到的小段的最大长度。如果连1cm长的小段都切不出来,输出”0”。

输入输出样例

输入 #1

3 7
232
124
456

输出 #1

114

 

 

 

 


题解

没想到二分法还有这么多变种的题目。我一直认为它只是一个小的知识点而已。

不过它的通用性还挺强的,碰到一个查找类的题都可以按这个思路优化以下。

 

这题就是练二分的入门题。

 

我先用了暴力。

 

代码

#include<bits/stdc++.h>
using namespace std;

int a[200000];

int main()
{
	int N,K;
	cin>>N>>K;
	
	for(int i=1;i<=N;i++)	cin>>a[i];
	
	int ans=0;
	for(int i=1; ;i++)		//段的长度 
	{
		int cou=0;
		for(int j=1;j<=N;j++)
		{
			cou += a[j]/i;
			if(cou>=K)	break;
		}
		if(cou>=K)
		{
			ans = i;
		}
		else
			break;
	}
	
	cout<<ans<<endl;
	return 0;
}

 

思路就是从段长最小的1一直增大了切,直到切的数量达不到K,那么上一个达到的就是最大段长。

 

最后,果然..

 

TLE 了一个点。

 

于是考虑二分法。

二分关键就在于找low和high这两端。

low明显就是1开始。

high,考虑最大。经过考虑,对于读入大量原木长度,若选取其中原木最大值,就很接近high的最大了。但最大在比那个最大值还要大的地方,也就是根本没有木段能切除那个长度(因为长度不够),此时切出的长度为0。

 

ac代码

#include<bits/stdc++.h>
using namespace std;

int a[200000];
int max_duan=0;
int N,K;

int tongji(int mid)
{
	int cou=0;					//单个记数 
	for(int j=1;j<=N;j++)
	{
		cou += a[j]/mid;
		if(cou>=K)	break;
	}
	return cou;
}

int main()
{

	cin>>N>>K;
	
	for(int i=1;i<=N;i++)
	{
		cin>>a[i];
		if(a[i]>max_duan)	max_duan = a[i];    //找最大长度
	}	
	
	int ans=0,cou=0;
	int low=1,high=max_duan+1;		//比最大长度还大(铁为0) 
	int mid;
	
	while(low<=high)
	{
		mid = (low+high)/2;		//中间段长 
		
		cou = tongji(mid);
		
		if(cou>=K)		//这里分两种情况
		{
			if(tongji(mid+1)>=K)	low = mid+1;
			else
			{
				ans = mid;
				break;
			}
		} 
		else
		{
			high = mid-1;
		}
	} 
	
	cout<<ans<<endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值