从木棒切割问题领悟二分法精髓

题目描述

给出n根木棒的长度,现在希望通过切割它们来得到至少k段长度相等的木棒(长度必须是整数),问这些长度相等的木棒的最大长度。

输入描述

第一行为两个正整数n、k(1≤n≤103、1≤k≤108),分别表示木棒的根数、需要得到的长度相等的木棒根数;

第二行为n个整数(1≤每个整数≤105),表示木棒的长度。

输出描述

一个整数,表示木棒的最大长度。如果无法达成,此时最大长度为0

思考

如果通过暴力解法,那么复杂度为O(n2)O(n2)。每轮选择一个长度遍历每根绳子。

已知木棒分割的长度为正整数,且位于[1,max(每根绳子的长度)][1,max(每根绳子的长度)]区间。当前为有序序列。求解至少k段长度相等木棒时,木棒的最大长度。

有序序列+求第一个满足某条件的元素的位置 => 二分法

已知木棒分割的长度序列从小到大,那么每个木棒长度对应的木棒段数序列从大到小

那么求木棒的最大长度,实际上在求最后一个 >= k 的木棒段数此时的木棒长度 。

但二分法是求第一个满足某条件的元素位置,为什么呢?不妨先试着编写求最后一个满足某条件元素位置的二分法。

假定序列从小到大排列,可以很容易写出下面三种情况。但在测试过程中,往往会出现死循环或没有输出的现象。

 第1、3种情况无论如何也会让 left<rightleft<right 不成立从而退出whilewhile循环。

那么很可能在第2种情况的时候陷入了死循环,求解一下死循环成立的条件。

left+right2=leftright2=left2这是C语言的整除left+right2=leftright2=left2这是C语言的整除

二分法求解给定的whilewhile条件是left<rightleft<right。显而易见,当left、right为相邻的奇偶时,且当 A[mid]==xA[mid]==x 时,会无限死循环,每轮都会进入第2种情况。

所以牢记二分法用于寻找有序序列第一个满足某条件的元素的位置。

题解很简单,我们只需要求第一个分段数小于k的木棒长度然后减1即可。

解法

highlighter- excel
<span style="background-color:#fafafa"><span style="color:#383a42">// htt<span style="color:#4078f2">ps:</span>//sunnywhy.com/problem/<span style="color:#986801">172</span>

// 考察二分查找

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>

<span style="color:#c18401">int</span> countSticks(<span style="color:#c18401">int</span> ans[], <span style="color:#c18401">int</span> <span style="color:#c18401">len</span>, <span style="color:#c18401">int</span> sep) {
    <span style="color:#c18401">int</span> total = <span style="color:#986801">0</span>;
    for (<span style="color:#c18401">int</span> i = <span style="color:#986801">0</span>; i < <span style="color:#c18401">len</span>; i++) {
        total += ans[i] / sep;
    }
    return total;
}

<span style="color:#c18401">int</span> main() {
    <span style="color:#c18401">int</span> <span style="color:#c18401">n</span>, k, ans[<span style="color:#986801">1010</span>], <span style="color:#c18401">max</span> = <span style="color:#986801">0</span>;
    // 加载数据
    scanf(<span style="color:#50a14f">"%d%d"</span>, &<span style="color:#c18401">n</span>, &k);
    for (<span style="color:#c18401">int</span> i = <span style="color:#986801">0</span>; i < <span style="color:#c18401">n</span>; i++) {
        scanf(<span style="color:#50a14f">"%d"</span>, &ans[i]);
        <span style="color:#c18401">if</span> (ans[i] > <span style="color:#c18401">max</span>) {
            <span style="color:#c18401">max</span> = ans[i];
        }
    }
    // 逻辑处理
    <span style="color:#c18401">int</span> <span style="color:#c18401">mid</span>, <span style="color:#c18401">left</span> = <span style="color:#986801">1</span>, <span style="color:#c18401">right</span> = <span style="color:#c18401">max</span>;
    while (<span style="color:#c18401">left</span> < <span style="color:#c18401">right</span>) {
        <span style="color:#c18401">mid</span> = (<span style="color:#c18401">left</span> + <span style="color:#c18401">right</span>) / <span style="color:#986801">2</span>;
        <span style="color:#c18401">if</span> (countSticks(ans, <span style="color:#c18401">n</span>, <span style="color:#c18401">mid</span>) < k) {
            <span style="color:#c18401">right</span> = <span style="color:#c18401">mid</span>;
        } else {
            <span style="color:#c18401">left</span> = <span style="color:#c18401">mid</span> + <span style="color:#986801">1</span>;
        }
    };
    printf(<span style="color:#50a14f">"%d\n"</span>, --<span style="color:#c18401">left</span>);

    return <span style="color:#986801">0</span>;
}
</span></span>

二分法固定模板

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bryan Ding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值