• 二分总结


    二分

    这是一个二分算法的总结

    对于算法来说,二分的确非常简单,被归类于基础算法,但是同样的,因为是基础算法,所以在竞赛中非常常用,今天距离CSP只剩下不到9天的时间了,我将利用这些时间对我的一些基础算法进行一些理解和总结,让csp得到尽量高的分数

    1.狭义二分

    当我们第一次见到二分的时候,我们是在一道题:

    从一个有序数列中找到某个数的位置,这道题因为数列是有序的满足单调性单调递增或者单调递减,所以我们可以使用二分算法,核心代码如下:

    //a为有序序列的数组
    int l=1,r=n;//n是数组的长度
    while(l<r){
        int mid=(l+r)/2;
        if(x<a[mid]) r=mid;//x为要查找的数字
        else l=mid+1;;
    }
    

    最后l即为最后的答案

    通过这个程序,我们知道了通过二分可以来进行对于查找的简化,大大降低时间复杂度,让程序运行更加高效,最主要可以获得更高的分数。

    2.广义二分

    因此我们从上面的例子可以明白,二分法实际上是对于一个单元函数具有单调性的时候,一个非常好的查找方法,因此我们可以运用这个方法到实际中,比如进行二分答案,快速查找答案

    二分答案有以下应用情景:

    平衡树查询第k大

    最小化最大值

    求第k大

    二分查找 lower_bound

    连续函数中值定理。区间中找到[mn,mx]中任一p的位置。

    集合中找出一个数。每次两个集合中至少有一个包含那个数即可

    下面一道经典例题,主要讲的是最小值最大的问题,同样这道题也有一些贪心的思想

    洛谷P2678 跳石头

    题目背景

    一年一度的“跳石头”比赛又要开始了!

    题目描述

    这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有(N)块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

    为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走(M)块岩石(不能移走起点和终点的岩石)。

    输入格式

    第一行包含三个整数(L,N,M)分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 (Lge 1且 Nge Mge 0)

    接下来 (N) 行,每行一个整数,第 (i) 行的整数(D_i (0le D_ile L)), 表示第(i)块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

    输出格式

    一个整数,即最短跳跃距离的最大值。

    输入输出样例

    输入 #1

    25 5 2 
    2
    11
    14
    17 
    21
    

    输出 #1

    4
    

    说明/提示

    输入输出样例 1 说明:将与起点距离为 2和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离21的岩石,或者从距离 21 的岩石跳到终点)。

    另:对于 20%的数据,(0le Mle Nle10)

    对于50%的数据,(0le Mle N le 100)

    对于 100%的数据,(0le M le N le 50,000,1le L le 1,000,000,000)

    思路

    首先,有n块岩石,然后每个岩石距离起点有一定的距离,并且是有序的,接着分析,我们可以移除m块石头,且不可以移除终点和起点的,目的是使最短跳跃距离的最大值。

    也就是说,这道题的目的是把最小距离最大化,因此我们设当移除dis块石头的时候,可以是最小距离最大化,这个最小距离的最大值为x。当当前石头和之前石头的距离小于dis的时候,我们就需要移走一块石头,因为我们设置的最小距离是dis,我们要使这个当前的时候和之前的石头的距离大于dis,这个时候就cnt(我们设置的计数器,用来统计需要移走的石头)加一。如果当当前石头和之前的石头的距离大于dis的时候,我们就不需要移走石头,也就是说这种情况符合题意,然后把之前的石头的距离x替换为当前的石头的距离,用于和下一块石头进行比较。

    由于当我们的距离dis越来越大的时候,我们需要移走的石头将会又来越多,所以这个函数符合单调递增的原则,因为我们需要找到一个值小于m,则当m大于cnt的时候就选择左区间进行查找,当m小于cnt的时候就选择右区间进行查找,这样循环下去,就可以找到最小距离的最大值。

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string>
    #include <cstring>
    using namespace std;
    int l,n,m,ans;
    int d[50005];
    bool check(int dis)
    {
    	int cnt=0,x=0;
    	for(int i=1;i<=n+1;i++)
    	{
    		if(d[i]-x<dis)
    		cnt++;
    		else x=d[i];
    	}
    	return cnt<=m;
    }
    int main()
    {
    	cin>>l>>n>>m;
    	for(int i=1;i<=n;i++)
    	cin>>d[i];
    	d[n+1]=l;
    	int left=0,right=l;
    	while(left<=right)
    	{
    		int mid=(left+right)/2;
    		if(check(mid)) left=mid+1,ans=mid;
    		else right=mid-1;
    	}
    	cout<<ans<<endl;
    }
    

    这是我目前对于二分的总结,之后将会继续总结,持续更新中

  • 相关阅读:
    lr文件下载脚本(文件参数化重命名)
    测试部工作不受重视怎么办?
    质量管理浅谈
    测试人员职业规划
    十年软件测试经验总结
    如何管理测试项目?
    ES性能测试
    将.dat文件导入数据库
    NLPIR_Init文本分词-总是初始化失败,false,Init ICTCLAS failed!
    JavaScript-也来谈--闭包
  • 原文地址:https://www.cnblogs.com/wweiyi2004/p/13886995.html
Copyright © 2020-2023  润新知