二分算法笔记及例题

先就这么写,写完过后,举例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是答案,推一次。 保证三次都能退出循环

相关推荐
Hammer_Hans1 小时前
DFT笔记112
笔记
tachibana21 小时前
RAGAS 指标解读
数据库·人工智能·算法·机器学习·架构·大模型·llm
FAREWELL000751 小时前
学习笔记-热更新导航
笔记·学习
qq_419563092 小时前
ToT 的 BFS/DFS 有个致命缺口:蒙特卡洛树搜索(MCTS)用「随机试错+统计」让大模型想得更深,小模型 + 它竟超过 GPT-4
算法·深度优先·宽度优先
苏子寒2 小时前
Nano-VLLM全代码解析笔记(6)-embed_head和linear
pytorch·笔记·python·机器学习·ai·nlp·vllm
万法若空3 小时前
CSP-J/S 排序算法完整专题训练题单
数据结构·算法·排序算法
凉茶钱3 小时前
【数据结构】排序(快排,选择,直接插入,希尔)
数据结构·算法·排序算法
weixin_446260853 小时前
拆解再复用:大模型智能体的跨任务技能迁移
人工智能·深度学习·算法
Brilliantwxx3 小时前
【Linux】 进程(4)七大进程状态深度解析
linux·运维·算法