【二分搜索 C/C++】洛谷P2440 木材加工

2025 - 02 - 19 - 第 56 篇
作者(Author): 郑龙浩 / 仟濹(CSND)
【二分搜索】

文章目录

洛谷P2440 木材加工

题目背景

要保护环境

题目描述

木材厂有 n n n 根原木,现在想把这些木头切割成 k k k 段长度均为 l l l 的小段木头(木头有可能有剩余)。

当然,我们希望得到的小段木头越长越好,请求出 l l l 的最大值。

木头长度的单位是 cm \text{cm} cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

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

输入格式

第一行是两个正整数 n , k n,k n,k,分别表示原木的数量,需要得到的小段的数量。

接下来 n n n 行,每行一个正整数 L i L_i Li,表示一根原木的长度。

输出格式

仅一行,即 l l l 的最大值。

如果连 1cm \text{1cm} 1cm 长的小段都切不出来,输出 0

输入输出样例 #1

输入 #1

3 7
232
124
456

输出 #1

114

说明/提示

数据规模与约定

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1≤n≤105, 1 ≤ k ≤ 1 0 8 1\le k\le 10^8 1≤k≤108, 1 ≤ L i ≤ 1 0 8 ( i ∈ [ 1 , n ] ) 1\le L_i\le 10^8(i\in[1,n]) 1≤Li≤108(i∈[1,n])。

变量

cpp 复制代码
//main函数
moods - 每个木头长度
num - 木头数量
equal_length - 等分的木头长度
equal_num - 需要的等分数量
max_mood - 最短的木头

//binary_searchSelf函数
left,right - 表示搜索范围
middle - 表示搜索范围的中间值
equal_NewNum - 实际等分数量
ans - 二分结果

思路

与 P1873 砍树 还是有些相似点的

首先,根据题目可以得出

  • 已知:木头数量,等分数量,每个木头长度
  • 求:最大等分长度

这个最大等分长度 肯定是在一定范围内求出来的,这个范围就是**[1, 最大木头的长度]**

实际上,刚开始写的时候,我的范围是[1, 最小木头的长度],我当时还以为,所有的木头都必须要分至少一个,所以我就将等分长度确定在了 1~最小木头的长度,但实际上,题目中并没有要求每个木头都必须要砍,所以我的想法是不正确的。

确定了范围,就要在这个范围中找到合适的等分长度 了,利用二分搜索法

二分搜索函数

  • 先确定开始的范围, left = 0, right = min_tree

  • 循环条件是:left <= right

  • 每次循环,都要计算 middle = (left + right) / 2,找到范围中间的值

    并且计算出,当等分长度为 middle 的时候,所有木头总共可以分成多少段

    因为每个木头长度可能不同,所以再写一个循环,计算出所有木头按照 middle 的长度分,能分多少段,这就要进行一个累加的操作,我将写一个变量 equal_NewNum 存储分段数量

  • 然后在计算完分段数量以后,判断是否 equal_NewNum == equal_num

    • 如果 ,则返回 middle(因为这个分段数量是在等分长度为middle的时候算的)
  • 判断是否 equal_NewNum < equal_num

    • 如果 ,则表示 分段数量 < 所需分段数量 ,进而得出分段长度++太长++ 导致 分段数量++过少++ 的结论
    • 此时就要调整 范围下限leftleft = middle + 1
  • 判断是否 equal_NewNum > equal_num

    • 如果 ,则表示 分段数量 > 所需分段数量 ,进而得出分段长度++太短++ 导致 分段数量++过多++ 的结论
    • 此时就要调整 范围下限rightleft = middle - 1

总结一下

  1. 确定最大等分长度范围
  2. 通过二分搜索在范围内找到等分长度,并返回
  3. 使用二分函数,打印返回结果

其中最重要的地方就是这个二分搜索 如何去写,其中有一些细节或特殊情况要判断进去,否则,过不了某些测试点

不过还有个特殊情况,我也没进行特判

如果连 1cm 长的小段都切不出来,输出 0

代码

cpp 复制代码
// 洛谷P2440木材加工
// 2025-02-18
// 郑龙浩/仟濹(CSDN)
//main函数
// moods - 每个木头长度
// num - 木头数量
// equal_length - 等分的木头长度
// equal_num - 需要的等分数量
// max_mood - 最短的木头

//binary_searchSelf函数
// left,right - 表示搜索范围
// middle - 表示搜索范围的中间值
// equal_NewNum - 实际等分数量
// ans - 二分结果
#include <iostream>
#include <algorithm>
using namespace std;
long long binary_searchSelf( long long moods[], long long num, long long equal_num, long long max_mood ){
    long long left = 1, right = max_mood; // 设置范围
    long long equal_NewNum = 0; // 实际等分数量
    long long middle = 0; // 范围中间值
    long long ans = 0;
    while( left <= right ){
        equal_NewNum = 0; // 每次累加之前都要重置
        middle = (left + right) / 2;
        // 计算实际等分数量
        // 就是计算每个木头按照 middle 可以等分多少段
        // 每层循环进行累加
        for( int i = 0; i < num; i ++ ){
            equal_NewNum += moods[ i ] / middle;
        }
        if( equal_NewNum >= equal_num ){
            ans = middle;
            left = middle + 1;
        } else {
            right = middle - 1;
        }
    }
    return ans;
}
int main( void ){
    long long num, equal_num; // 木头数量 分段数量
    cin >> num >> equal_num; // 输入木头数量 + 分段数量
    long long moods[ num ] = {0}; // 木头数据 -> 每个木头的长度
    long long max_mood = 0;
    for( int i = 0; i < num; i ++ ){
        cin >> moods[ i ];
    }
    sort( moods, moods + num ); // 升序排序
    max_mood = moods[ num - 1 ]; // 最长木头
    cout << binary_searchSelf( moods, num, equal_num, max_mood );
    return 0;
}
相关推荐
干炒 牛河28 分钟前
数据结构:哈希表(unordered_map)
数据结构·算法·散列表
令狐掌门1 小时前
C++中间件DDS介绍
c++·中间件·c++ dds
我不是程序猿儿4 小时前
【C】识别一份嵌入式工程文件
c语言·开发语言
Dizzy.5175 小时前
数据结构(查找)
数据结构·学习·算法
专注VB编程开发20年7 小时前
除了 EasyXLS,加载和显示.xlsx 格式的excel表格,并支持单元格背景色、边框线颜色和粗细等格式化特性
c++·windows·excel·mfc·xlsx
分别努力读书7 小时前
acm培训 part 7
算法·图论
武乐乐~7 小时前
欢乐力扣:赎金信
算法·leetcode·职场和发展
'Debug8 小时前
算法从0到100之【专题一】- 双指针第一练(数组划分、数组分块)
算法
Fansv5878 小时前
深度学习-2.机械学习基础
人工智能·经验分享·python·深度学习·算法·机器学习
子豪-中国机器人8 小时前
2月17日c语言框架
c语言·开发语言