淼淼的二分

        继续闲聊:记得蒋大佬跟我说过那个二分都不能叫算法,一写就写出来了,啊啊啊啊,感觉跟人家的水平确实有所差距,当时真的连二分算法都写不出来,现在呢,虽然没有特别的精通,但好歹是能写出来了,那就说一下我对二分的总结吧。

1.二分的模板

bool check(int x){}//重点是将check函数写出来
int ans = -1;
int low=1;
int high = n;
while (low <= high) {
	int mid = (low + high) / 2;
	if (check(mid)) {
		ans = mid;
		low = mid + 1;//比它更优的都在它的右边
	}
	else {
			high = mid - 1;//说明此时条件大了,不满足当前出口的条件,所以向左查找。
	}
}
		return ans;//返回ans

2.二分查找(OlogN)

 上代码:

#include <iostream>
using namespace std;
int n;int m;
int a[100];
int ans = -1;
int binary_search(int a[], int n, int x) {
    int left = 1;
    int right = n;
   
    while (left <= right) {
        int mid = (left + right) / 2;
        if (a[mid] ==x) {//边界的条件,符合这个数就可以停止查找了
            ans = mid;
            break;
        }
        else if (a[mid] < x) {
            left = mid + 1;
        }
        else {
            right = mid - 1;
        }
    }
    return ans;
}
int main()
{
    cin >> n>>m;
    for (int i = 1; i <=n; i++) {
        cin >> a[i];
    }
    binary_search(a, n, m);
    cout << ans << endl;
}

完美输出! 

       借鉴了五点七边的“二分查找为什么总是写错”更新之后代码为:(赖大佬推荐的)二分查找为什么总是写错?_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1d54y1q7k7

#include <iostream>
using namespace std;
int n; int m;
int a[100];
int ans = -1;
int binary_search(int a[], int n, int x) {
    int left =0;//搜索的第一个数字为1时,左边界定义为0即可,这样的话不会溢出
    int right = n;
    //不会出错的二分模板
    while ((left + 1) != right) {
        int mid = (left + right) / 2;
        if (a[mid] == x) {//边界的条件,符合这个数就可以停止查找了
            ans = mid;
            left = mid;
        }
        else {
            right = mid;
        }
    }
    return ans;
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i<=n; i++) {
        cin >> a[i];
    }
    binary_search(a, n, m);
    cout << ans << endl;
}

2.二分答案

例题开始:

P2440 木材加工

题目背景

要保护环境

题目描述

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

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

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

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

输入格式

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

接下来 nn 行,每行一个正整数 L_iLi​,表示一根原木的长度。

输出格式

仅一行,即l的最大值。

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

输入输出样例

输入 

3 7
232
124
456

输出 

114

P2440 木材加工 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2440

        题目分析:二分的模板是固定的,主要是要写出什么?那就是check函数,那该怎么写?

        首先是个数一定要>=所给的段数,然后找到它的一个边界值,然后这个L到r的取值该如何?

        L=1(因为题目中明确说明了不得小于1cm),那最大的边界定为多少呢?当然是所给木块长度的最大值说不定它就让你取一个呢),所以就有一个bool函数:

bool check(int mid) {
    long long sum = 0;//数据比较大
    for (int i = 1; i <= n; i++) {
        sum += len[i] / mid;
    }
    return sum >= k;//大于等于k才是正确的
}

于是就套模板呗:(本人不喜欢伪代码,代码写出来就是让人看得懂,觉得美)

#include <iostream>
#include <algorithm>
using namespace std;
int n; int k;
int len[100100];
bool check(int mid) {
    long long sum = 0;//数据比较大
    for (int i = 1; i <= n; i++) {
        sum += len[i] / mid;
    }
    return sum >= k;
}
int main()
{
    cin >> n >> k;
    int ans = 0;
    int maxn=-100;
    for (int i = 1; i <= n; i++) {
        cin >> len[i];
        maxn = max(maxn, len[i]);
    }
    int low = 1;
    int high = maxn;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (check(mid)) {
            ans = mid;
            low = mid + 1;//向右边搜索,试图去找到更优的解
        }
        else {
            high = mid - 1;//条件不符合,向左边搜寻能满足条件的数
        }
    }
    cout << ans << endl;
}

更新后:

#include <iostream>
#include <algorithm>
using namespace std;
int n; int k;
int len[100100];
bool check(int mid) {
    long long sum = 0;//数据比较大
    for (int i = 1; i <= n; i++) {
        sum += len[i] / mid;
    }
    return sum >= k;
}
int main()
{
    cin >> n >> k;
    int ans = 0;
    int maxn = -100;
    for (int i = 1; i <= n; i++) {
        cin >> len[i];
        maxn = max(maxn, len[i]);
    }
    int low =0;//此时为什么要标记成0,因为最小的条件为1,比最小的条件减一就不会溢出
    int high = maxn;
    while (low+1!=high) {//无非就是两个指针的移动
        int mid = (low + high) / 2;
        if (check(mid)) {//符合条件的进入
            ans = mid;
            low = mid;//向右边搜索,试图去找到更优的解
        }
        else {
            high = mid;//条件不符合,向左边搜寻能满足条件的数
        }
    }
    cout << ans << endl;
}

所以总结下来改进的模板就是:

    int left =0;//搜索的第一个数字为1时,左边界定义为0即可,这样的话不会溢出
  //int left=-1;//搜索的第一个数为0时,定义左边界为-1
    int right = n;
  //不会出错的二分模板
    while ((left + 1) != right) {
        int mid = (left + right) / 2;
        if (a[mid] == x) {//边界的条件,符合这个数就可以停止查找了
            ans = mid;
            left = mid;
        }
        else {
            right = mid;
        }
    }
    return ans;

        大大保证了二分算法不会出错,目前二分的掌握暂时性到这里,以后会更新二分查找中浮点数的该如何去写,感谢各位大佬们的鼎力相助,才让本菜菜得以掌握二分的基础,感谢观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

钟一淼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值