折半查找 及 砍树 · 木材加工 题解

二分

折半查找

代码模板

while(l<=r)
{
    
    
	int mid=(l+r)/2;
	if(check(mid))
	{
    
    
		ans=mid;
		l=mid+1;
	}
	else
	{
    
    
		r=mid-1;
	}
}

砍树

https://www.luogu.com.cn/problem/P1873

题目描述

伐木工人米尔科需要砍倒M米长的木材。这是一个对米尔科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,米尔科只被允许砍倒单行树木。

米尔科的伐木机工作过程如下:米尔科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。米尔科就行到树木被锯下的部分。

例如,如果一行树的高度分别为20,15,10和17,米尔科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而米尔科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。

米尔科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助米尔科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。

输入格式

第1行:2个整数N和M,N表示树木的数量(1<=N<=1000000),M表示需要的木材总长度(1<=M<=2000000000)

第2行:N个整数表示每棵树的高度,值均不超过1000000000。所有木材长度之和大于M,因此必有解。

输出格式

第1行:1个整数,表示砍树的最高高度。

输入输出样例

输入 #1
5 20
4 42 40 26 46
输出 #1
36

本题中,check的检查内容即为 所得到的树的高度总和 是否符合题目

代码

#include <iostream>
#include <string>
using namespace std;

int n,m;
int ans=0;
int l=0,r=0;
int tree[1000005]={
    
    0};//注意数据范围

bool check(int x)
{
    
    
	long long s=0;//注意数据范围
	for(int i=1;i<=n;i++)
	{
    
    
		if(tree[i]>x)//判断第i棵的高度是否比锯片的高度高
		{
    
    
			s+=tree[i]-x;//将树砍下的高度累加
		}
	}
	return s>=m;//将高度和与需求高度m比较
}

int main()
{
    
    
  
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
    
    
		cin>>tree[i];
		r=max(r,tree[i]);//存放最大值!
	}
  	
  	while(l<=r)//简单的对半查找
  	{
    
    
  		int mid=(l+r)/2;
  		if(check(mid))
  		{
    
    ;
  			l=;
		}
		else
		{
    
    
			r=;
		}
	}
  	
  	cout<<ans;//完美输出!
  	
 	return 0;
}

搞定一题,下一题:

木材加工

https://www.luogu.com.cn/problem/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

此题中,check用来判断 被切割的段数是否符合题目要求

代码

#include <iostream>
#include <string>
using namespace std;

int n,k;//N是原木的数目,K是需要得到的小段的数目
int treelen[100005]={
    
    0};
int l=0,r=0;
int ans=0;

bool check(int x)
{
    
    
	int s=0;
	for(int i=1;i<=n;i++)
	{
    
    
		if(x<=treelen[i]&&x!=0)//若能切割且切割长度>=1
		{
    
    
			s+=(treelen[i]/x);//段数
		}
		else if(x==0)//无法切割(长度<1)
		{
    
    
			return s=0;//无法切割即段数为0
		}
	}
	return s>=k;//返回条件!!!!
}

int main()
{
    
    
    
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
    
    
		cin>>treelen[i];
		r=max(r,treelen[i]);//存放最大值
	}
	
	while(l<=r)//简单的对半查找
	{
    
    
		int mid=(l+r)/2;
		if(check(mid))
		{
    
    ;
			l=;
		}
		else
		{
    
    
			r=;
		}
	}
  	cout<<ans;//完美输出
  	
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Joseph_tony/article/details/108560804
今日推荐