二分答案

时间:2020-05-30
本文章向大家介绍二分答案,主要包括二分答案使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

这是一个对二分答案的总结

首先明确的概念是:二分查找虽然是在中点处截取,但是随着截取的越来越精细,是可以确定把答案落在一个具体值身上的

根据二分查找的这个特性,可以快速的在可枚举的数据中进行定位

使用二分答案的条件:

1.可枚举

2.序列呈现递增的形态(这也契合二分查找的要求)

3.

下面上例子!

18725 宇宙迁跃

时间限制:1000MS  代码长度限制:10KB
提交次数:0 通过次数:0

题型: 编程题   语言: 不限定

Description

在基地的科学家发明“透镜”之后,宇宙航行变得更加效率。
作为基地元首的的代理人,你需要在K天内乘坐飞船到达首都川陀。
飞船可以花费一天时间,通过迁跃从一个星系到达另一个星系,但绝不能迁跃到星系之间,那样不但会遇到一些自然危险,也可能永远迷失。
我们把基地至川陀间星系的坐标看成是一个线性序列,例如a星系坐标是10,b星系坐标是15,那么飞船必须具备不小于5的迁跃能力才能从a航行至b。
基地坐标为0,请你根据基地至川陀间的N个星系坐标,计算飞船的迁跃能力至少为多大,才能在K天内(包含K天)到达川陀。




输入格式

第一行两个整数N和K。(1=<N<=10000,1=<K<=10000)
第二行N个整数,表示N个星系的坐标ai,题目确保坐标由小到大排列。(0=<ai<=100000)



输出格式

仅一行,飞船的最小迁跃能力。



输入样例

5 2
1 4 6 10 19



输出样例

10



提示

样例说明:川陀的坐标为最后一个值19。
飞船的迁跃能力至少为10,才能在2天内到达川陀。

对这个例子的分析:

用常规思路来思考:从1开始枚举,每个节点,每个都试探能不能成功飞行,这是OK,而且枚举的过程也是从1开始不断增大的

所以我们在main函数里面 通过二分查找在茫茫的范围内通过二分查找来定位最终的答案

ps:总有一个最终的答案ans这是一个临界值,比这个答案小一点的,飞船飞不过去,比这个答案大一点的,飞船都可以飞的过去,所以称之为至少!

main函数里面是常规的二分模板                             check 函数是判断是对mid的判断

如何构造check来进行判断???

check(int mid)     //由于要判断,满足的条件有两个:1.飞船可以成功跃迁(如果都跳不过去,那换一个更大的试一下,所以反馈回去,应该是定位到折半查找的左半段)

                                                                                           2.天数不会超过要求的值(这里要求至少,那肯定是把给定的天数都用掉,才可能尽可能的小),这个用一个计数器

{

       跃迁判定:1.相邻点都跳不过去,太菜了,还是找一个更大的吧,直接return 0;

                         2.相邻点可以跳过去,那就一直i++,直到在某个点卡住了(那还是可以找落脚点的,大不了一个个格子跳)

                             由于是用for来进行循环的,能够走到这一步,说明上一个点是可以跳过去的,就如下图所示,此时要做两件事情

                                  ①把a[i-1]设置为落脚点,更新落脚点的位置pre=a[i-1]

                                  ②记录跳跃次数 c++;

!!!!!!!!!!这里有一个非常非常非常容易错的地方,跳跃次数的更新,是当某个点被卡住的时候才会更新,试想一下,现在的跳跃能力超级无敌强,那检测到最后一个格子,他都不会被卡住,那记录的跳跃次数将为0,也就是说,当跳跃能力很强的时候,最后一个点是不会被记录的,所以要人为的在检测的最后,把跳跃次数加一次(最后一跳)

}

上代码

#include<iostream>
using namespace std;
int a[10005],n,k;
int check(int x)
{
    int i=1,c=0,pre=0;
    while(i<=n&&c<=k)
    {
      if(x<a[i]-a[i-1])return 0;//如果都不支持相邻点之间的条约,那么不用再考虑
      if(a[i]-pre>x)//如果现在到这个点跳不过去了,那就跳到前一个点(因为是逐个循环,前一个点肯定可以到),那么从这轮开始pre就是a[i-1] 
      {
          pre=a[i-1];
          c++;//记录跳跃的次数,需要多跳一次了 
       } 
          else i++;
    }
    c++;  //前面测试了可行性,但是不会记录最后一跳,补最后一天!! 
    return c<=k;
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j,k;
    cin>>n>>k;//记录站点的数量 天数 
    for(i=1;i<=n;i++)  //读入数据 
        cin>>a[i];
    int l=1,r=1000000,mid,ans;
    while(l<=r)
    {
        mid=(l+r)/2;//这是二进制位往左移动一格,意思就是/2 
        if(check(mid))
        {
            ans=mid;
            r=mid-1;
         } 
         else l=mid+1;
    }  //在这个部分采用二分搜索的方法,在茫茫的数字中寻找那个临界点 
    cout<<ans;
    return 0;
}

原文地址:https://www.cnblogs.com/wengst/p/12993500.html