二分算法笔记及例题

先就这么写,写完过后,举例3个数据,分别假设这三个数据是答案

当既不会出现死循环,又能输出正确答案,那就是对的

eg.找到4是一个答案,l=mid+1。如果5不是答案 和 如果5是答案, 看看能不能退出循环

二分查找的应用----二分答案(猜答案)

步骤:1.确定题目是二分的题目 2.确定答案的范围 3.假定中间位置是否可行 4.通过判断不断二分缩小范围

题型:

1.求最值 ---->可能用二分

2.最小化最大值 3.最大化最小值 ---->一定用二分

求最值

例题1:

P1873 COCI 2011/2012 #5 EKO / 砍树 - 洛谷

时间复杂度 O(n*lg(r-l))

cpp 复制代码
#include<iostream>
#include<cmath>
using namespace std;
int tree[1000005];  //每棵树的高度

int N;long M; //树的个数,所需木材(1≤M≤2×10^9,刚好int)

bool check(int mid, int maxh)
{
    //cout << "mid=" << mid << " ";  调试
    long long sum = 0; //可能超过int
   // for (int i = 1; i <= maxh; i++) {     数组和下标都弄混淆了
   //     if (mid < h[i]) {
   //         sum += h[i] - mid;
   //     }
   // }
    //cout << "sum=" << sum << ",M=" << M << " ";

    for (int i = 1; i <= N; i++)
    {
        if (mid < tree[i])
        {
            sum += tree[i] - mid;
        }
    }


    if (sum >= M) return true;
    else return false;
}

int main()
{
   
    cin >> N >> M;
    int maxh = 0;
    for (int i = 1; i <= N; i++) {
        cin >> tree[i];
        maxh = max(maxh, tree[i]);
    }

    //二分区间
    int l = 0, r = maxh;
    int ans = 0;
    while (l <= r) {
        int mid = (l + r) / 2;
        if (check(mid,maxh)) { //若合法,因为找最大值,所以先记录答案,再往更大的方向找
            ans = max(ans, mid);
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    }
    cout << ans;
}

最大化最小值和最小化最大值

最小化最大值 在5个班里面最高的个子中挑一个最矮的

最大化最小值 在5个班里面最矮的个子中挑一个最高的

最大化最小值题目: 某个情景,求一个最大化最小值

二分最小值

l,r mid--->最小值---->反推题目给出的另一个条件-----

(如果不满足,说明还不够小,往小方向取;如果满足,再增大(最大化最小值),看能不能更大化)

最大化最小值题目:满足 最大化,不满足减小化

2.例题P2678 NOIP 2015 提高组 跳石头 - 洛谷

最大化最小值题目:满足则最大化,不满足则 减小化 (注意这点)

Q1:什么叫做最短跳跃距离

2

Q2:什么叫做最短跳跃距离最大化

题目允许你移走岩石,这样会改变岩石的分布,于是就会得到新的最短距离。

移走一个时,移走两个时(<=m) ... 求出一个最短距离最大的数。

Q3: 确定跳跃距离的范围

(每个岩石都是挨着的) 1 ~~ L (直接跳到终点) mid=(1+L)/2 然后得找大于等于mid的岩石

如果两个岩石之间的距离大于mid,不动。如果AB距离小于了mid,要移动(因为mid一定是最短移动距离)

那问题是移动A还是移动B?

1.A是起点,移动B 2.B是终点,移动A 3.A,B在中间,A/B

Q4:如果发现移动的岩石大于了m,那说明mid怎么样?

说明mid取大了,因为小于mid的才会被移动,mid太大了就会导致岩石移的多

最大化最小值题目:满足则最大化,不满足则 减小化

往左走,二分找7。 7还大了,找4,4时刚好移走m 求的是最大化,刚好移动m时是最大化最小值

Q5:怎么去比较两个岩石之间的距离和统计移走岩石数目?

两个指针now,和next。now指向岩石起点,next往右走,判断之间的距离

如果小于mid,cnt++(怎样移走在代码中不用体现出来)。如果大于mid,now才移动到next的位置

时间复杂度 O(nlgL)

cpp 复制代码
#include<iostream>
using namespace std;
int S, N, M;  //距离,起点终点之间的岩石数,至多移走的
int dis[50005];  //统计每个点到起点的距离.  下标N+1
//int res[1000000005]; //答案数组 

bool check(int mid)//判断合不合法:即是否移走不多于M块岩石
{
    //双指针
    int now = 0, next = 0;  //两块岩石的起点,终点
    int cnt=0; //统计移走的数目
    for (next = 1; next <= N + 1; next++) {
        if (mid > dis[next] - dis[now]) {
            cnt++;  //代码中不用体现岩石是怎么移走的
        }
        else {  //距离合法,now可以移动过去了
            now = next;
        }
        if (cnt > M) break;
    }
    if (cnt <= M) return true;
    else return false;
}

int main()
{
    cin >> S >> N >> M;
    dis[0] = 0;  //起点
    dis[N + 1] = S; //终点
    for (int i=1; i <= N; i++) {
        cin >> dis[i];
    }

    //答案区间1~~S
     //二分法
    int l = 1, r = S;
    int ans = 0;
    while (l <= r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            ans = max(ans, mid);  //可能是答案,保存下来
            l = mid + 1;
        }
        else r = mid - 1;
    }
    cout << ans;
}

总结题目类型:

1.求最值

2.最大化最小值/最小化最大值

3.用于枚举优化---->logn

另外注意:

二分的代码不唯一,四个地方要配合起来,只要不出现死循环就行---->方法:拿三个数据去模拟一下

假设3是答案,推一次。假设4是答案,推一次。假设5是答案,推一次。 保证三次都能退出循环

相关推荐
疯狂打码的少年8 分钟前
【计算机网络】子网掩码与子网划分计算(含CIDR表示法)
服务器·笔记·计算机网络·php
Msshu12320 分钟前
2~5串锂电快充优选|XSP36 Type‑C升压/升降压快充管理芯片
数据结构·随机森林·贪心算法·排序算法·线性回归·启发式算法
shirsl1 小时前
算法 Day 2 滑动窗口 + 栈 / 单调栈
开发语言·python·算法
自小吃多2 小时前
PCB Editor软件复制、改变、删除操作笔记
笔记·嵌入式硬件
土司大王2 小时前
LeetCode hot100 回溯专题总结:Java 通用模板、决策树模型
java·算法·leetcode·决策树
2601_962218612 小时前
万象生鲜系统订单全生命周期状态同步技术实现业务可视
大数据·数据库·人工智能·python·算法
那年窗外下的雪.2 小时前
AIDC 学习日志|第 22 天|All-Active/Single-Active 故障演练设计
服务器·网络·学习·算法·哈希算法
m0_734571762 小时前
深入理解C++ 析构函数<一>基本概念
开发语言·c++
wzdark3 小时前
基于启发式搜索的最优路径规划算法研究4
算法
动词ing3 小时前
【学习笔记】数据结构栈与队列(栈先进后出+队列先进先出+括号匹配+消消乐模型)
数据结构·笔记·学习