二分查找——Binary Search

原理就类似于下图啦(网上看到哒,忽略这个代价)
二分的时间复杂度一般是 O(logN) 的,超开心了有木有٩(๑>◡<๑)۶
最简单来说,它可以分为整数二分和实数二分两类题型,套路和注意点都值得思考喔

整数二分

Rikka with Mutex
hznu19training题源

Background
Sometimes, technical terms implicate some life philosophy. Mutex is one of them. On your way to dream, you may be locked by some difficulties, and you need someone to stop his step, and help you get through them.
To help you know better about the life philosophy inside mutex, Rikka comes up with a simple task. Maybe some of you know little about mutex, so she uses another scene to replace it.
There are n gates in a row, several people in the left side of the gates and all of them want to go to the right side. There are two kinds of gates: black and white. These people share energy, which is represented by a non-negative number E. Initially, E=0.
If one person walks through a white gate, he will gain one point of energy, i.e., E will be added by 1. And if one person walks through a black gate, he will lose one point of energy, i.e., E will be subtracted by 1. Since E must be a non-negative integer, if E=0, no one can walk through a black gate until someone walks through a white gate. You can assume there won’t be two people moving at the same time and all the people are selfless.
We use P to represent a black gate, V to represent a white gate and use a PV string to represent the row. Initially, all the people are at the beginning of the string, and all of them want to go through the whole string. But unfortunately, sometimes it may be impossible. So, they want to send at least one person to the right side.
Your task is to find out the minimal number of people which this group needs to achieve this goal.
For example, if the row is VPP, they need at least two people: The first person walk through the first white gate and the second person can use this point of energy to go through the whole string.

Input
The first line contains a single numner t(1≤t≤103), the number
of the testcases. For each testcase, the first line contains a PV
string s(1≤|s|≤105) describing the gates. The input guarantees that
there are at most 30 testcases with |S|>1000.

Output
For each testcase, output a single integer, the answer. And if it is impossible, output −1.

Sample Input
4
VPP
VPPVVVVPPPPPPPP
VPPPPPPPPPPPPPP
P

Sample Output
2
3
14
-1

理解-中文题意
  • 输入一个字符串string,字符串的长度就是门的个数,V代表白门,P代表黑门
  • 一个人通过一扇V时,总的能量增加1,通过一扇黑门,总的能量减少1
  • 当能量小于0的时候不能通过黑门
  • 初始能量每个人都是0,那么总能量池也是0
  • 问至少一个人通过全部门,最小需要几个人
注意-题意敲重点
  • 所有人共用能量,无论谁通过了哪扇门,总的能量池都会变化
  • 比如10个人一起通过V,那么能量池里的能量就+10
  • 最后的目的就是,总的能量够至少一个人自己走到终点
思路-情景模拟
  • 如果有一排门VVVPPPP
  • 可以先让一个人去试探——冲锋陷阵.jpg
  • 如果他往前走到某个位置,总能量上涨
  • 那么其余的人都可以跟上来到这个位置
  • 因为一个人涨,大家一起过来,就会涨得更多
  • 一个人跌,大家一起过来,只会跌得更多
  • 所以要保证实现最大的能量,然后用这些能量护体保冲锋军平安
二分-解题突破
  • 如果第一扇门就是P,无论怎么走,谁走,能量池都将变成负数

  • 所以只有当第一扇门不是P的时候才有可能实现计划(接下来的阐述假设第一扇门不是P)

  • 最糟糕的情况就是第一扇门是V,后面全部是P

  • 那么,包括第一扇门一共len扇门,最多只要安排len-1个人就够啦

  • 所以二分的对象是人数!!!每次只要验证这个人数能否满足题意即可啦

  • 【mid变量】找人数

  • 【total变量】能量池

  • 【solve函数】判断是否可以解决题目的问题

  • 如果人数满足,那么别忘了试试更小的数,毕竟是找最少要多少人嘛(o゚▽゚)o

好啦~有思路咯,那就快来写代码叭。◕ᴗ◕。

#include<stdio.h>
#include<string>
#include<iostream>
using namespace std;
string put;
int check(int mid)
{int len=put.length(),total=0,before=total;for(int i=0;i<len;i++){if(put[i]=='P') total--;else total++;//先让一个人冲锋陷阵if(total<0) return 0;//冲锋军阵亡else{if(total<=before) continue;//冲锋军正在试探ingelse//冲锋军不辱使命找到了能量池增长的位置{total+=mid-1;before=total;}}}return 1;
}
int main()
{int T;cin>>T;while(T--){cin>>put;if(put[0]=='P') printf("-1\n");else//二分所需要的人数,1-put.length() {int left=1,right=put.length(),mid;while(left<=right){//left==right的时候还要判断是否可以check,如果不可以,还要放大一位 mid=(left+right)>>1; //用>>1位移代替/2时间复杂度更小if(check(mid)) right=mid-1;else left=mid+1;}cout<<left<<endl;}}return 0;
}

实数二分

Cable master
HZNU19training题源

Background
Inhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Committee has volunteered and has promised to organize the most honest contest ever. It was decided to connect computers for the contestants using a “star” topology - i.e. connect them all to a single central hub. To organize a truly honest contest, the Head of the Judging Committee has decreed to place all contestants evenly around the hub on an equal distance from it.
To buy network cables, the Judging Committee has contacted a local network solutions provider with a request to sell for them a specified number of cables with equal lengths. The Judging Committee wants the cables to be as long as possible to sit contestants as far from each other as possible.
The Cable Master of the company was assigned to the task. He knows the length of each cable in the stock up to a centimeter, and he can cut them with a centimeter precision being told the length of the pieces he must cut. However, this time, the length is not known and the Cable Master is completely puzzled.
You are to help the Cable Master, by writing a program that will determine the maximal possible length of a cable piece that can be cut from the cables in the stock, to get the specified number of pieces.

Input
The input consists of several testcases. The first line of each testcase contains two integer numbers N and K, separated by a space. N (1 ≤ N ≤ 10000) is the number of cables in the stock, and K (1 ≤ K ≤ 10000) is the number of requested pieces. The first line is followed by N lines with one number per line, that specify the length of each cable in the stock in meters. All cables are at least 1 centimeter and at most 100 kilometers in length. All lengths in the input are written with a centimeter precision, with exactly two digits after a decimal point.
The input is ended by line containing two 0’s.

Output
For each testcase write to the output the maximal length (in meters) of the pieces that Cable Master may cut from the cables in the stock to get the requested number of pieces. The number must be written with a centimeter precision, with exactly two digits after a decimal point.
If it is not possible to cut the requested number of pieces each one being at least one centimeter long, then the output must contain the single number “0.00” (without quotes).

Sample Input
4 11
8.02
7.43
4.57
5.39
0 0

Sample Output
2.00

理解-中文题意
  • 给出N条线段,以米的单位给出,小数点后两位(精确到厘米)
  • 现在要对这些线段裁剪,裁剪出K条等长的线段
  • 并且让这些线段尽可能长另外线段的长度不能小于1厘米
  • 输出要精确到小数点后两位,如果筹不够K条,输出0.00
注意-题意敲重点
  • 要精确到小数点后两位喔!!!为了完美逼近,需要开个eps精确量(如1e-5)
  • 对于输入的数据无需排序,因为得到的答案不一定是在输入的数据值里
  • 有些在输入数据中寻找答案的,则要排序后对下标进行二分
  • 初始只要记录最大值做右边界,再用其中一个数据分K段做左边界即可
  • solve函数判断记录能分的段数的时候,等于K的也要再将mid扩大尝试!!!
  • 因为答案是小数,K是整数
  • 11.09cm的线段分成11.05cm和11.08cm都是分出1段,K都是1
  • 而小数点后第二位是5还是8,就影响了题中的精确度
二分-解题突破
  • 这题思路不难,重点在于精确度

  • 只要对每单的长度进行二分预测,然后验证实际能不能分出K段这个长度

  • 如果不能分出,每段就要更小;如果可以分出,就试试更大的每段的长度能否拥有K段

  • 所以二分的对象是每段的长度!!!每次只要验证这个长度能否满足题意即可啦

  • 【mid变量】找分成多长

  • 【eps精确量】实现题意精确度,尽量开小点叭,一般1e-5/1e-6的样子,太大可能wa

  • 【solve函数】判断是否可以真的可以分mid长度分出K段

  • 如果人数满足,那么别忘了试试更大的数,毕竟是找最长每段能分出多长嘛(o゚▽゚)o

好啦~有思路咯,那就快来写代码叭。◕ᴗ◕。

#include<iostream>
using namespace std;
double put[10010];
double eps=1e-5;
int n,k;//n是现有多少段电缆,循环输入;k是需要多少段电缆
bool solve(double mid)
{long long num=0;for(int i=0;i<n;i++){long long t=int(put[i]/mid);/*int()是C++的强制转换,(int)是C的强制转换 int()是一种单目运算符,此处运用相当于取整 */ num+=t;}if(num>=k) return 1;else return 0;
}
int main()
{while(~scanf("%d %d",&n,&k))//不停地输入现有段数 & 所需段数 {if(n==0&&k==0) break;double right=0.0;for(int i=0;i<n;i++){//循环输入现有段数每段多长 scanf("%lf",&put[i]);if(put[i]>right) right=put[i];//right记录现有的最长段}double mid,left=put[0]/k;/*left初始记录满足第一个输入的分段长度因为满足所有的输入,则必然满足第一个输入循环二分需要初始一个左边界left那么left要有可能性是答案则必须满足其中一个能被分成K段*/while(right-left>eps)//1的-5次方不一定,可依据题意开 {//二分被切成的长度,注意精确度 mid=(right+left)/2;if(solve(mid)) left=mid;//如果处理mid发现满足题意那再去找更大的值 else right=mid;//不满足solve就去找更小的值 }//循环终止时,left和right趋近相等,进行输出printf("%.2f\n",left);}return 0;
}

关于二分的一些小思考…

solve函数只要验证二分到的mid能否满足题意即可
然而…left和right的变化+退出+输出应该是最头大的问题了叭

一般情况对于变化

  • 变化的时候 一般都是 left=mid+1;right=mid-1;
  • 不然会造成重复比较和死循环(整数二分)
  • 但为什么上述分线段的可以 left=mid;right=mid;
  • 因为这个题是实数二分,判断循环结束不是靠left<=right
  • 整数二分里面left永远小于right,退出循环是靠达到了预设的精确量呢

一般情况对于退出

  • 如第一道VP门题,是left<=right的循环条件,>的时候退出
  • 关键就在于这个等号
  • 因为当left和right相等的时候
  • 可能是前一个mid满足,right=mid-1;也可能是前一个mid不满足,left=mid+1
  • 总之被试solve的都是mid,相等时left和right都没被试过
  • 只有试试才知道这个新的人数能否满足solve的题意

  • 如第二道分线段题,是right-left>eps的循环条件,<=的时候退出
  • 这个就是为了足够精确,当然没必要等于啦
  • 设1e-5的eps就是希望它更小再退出嘛,达到1e-5就达到我的期望啦
  • 不然干嘛不设1e-6呢哈哈哈

注意第一题相等的时候没试过solve所以要=;第二题相等的时候精确度不够小不要=
所以一般整数二分要等号;实数二分不要等号
但具体还是得根据题意进行判断喔,免得栽在奇葩题目里哈哈哈哈哈

一般情况对于输出

  • 如第一道VP门题,输出的是left
  • 那是因为我们要找更小的那个人数
  • 满足solve的题意的时候,是right减小
  • 如果最后left=right的时候,mid通过了solve,要找更小的数
  • 那么right会减小,显然结果小于了left,不在范围内
  • 而left没变,也就是那个通过了的solve
  • 如果最后left=right的时候,mid没通过solve,要找更大的数
  • 那么right没变,显然这个值不满足题意
  • 而left增大,left>right,right变小的前提都是为了找更小的满足条件的答案
  • 大于right的范围都满足了题意,所以可以输出left

  • 如第二道分线段题,输出的是left
  • 那是因为要找分出的更长的线段
  • 满足solve的题意的时候,是left增大
  • 当即将实现right-left<=eps退出循环时,left满足solve
  • 本来还是>eps,现在要差值变小
  • 要么是mid满足solve,lef增大;要么是mid不满足solve,right减小
  • 注意整数二分,因为是整除,可能出现left==right,二分后的mid又与它们相等
  • 但是实数二分,mid出现小数位的变动一定不会与left、right相等
  • 进行变化的时候,都是left=mid,right=mid
  • 所以mid是否满足solve就代表了left或者right是否满足solve
  • 最后输出的当然得是满足solve的left啦(就算mid不满足solve,之前保存的left也依旧满足solve鸭)

注意第一题满足solve时,right减小;第二题满足solve时,left增大
第一题要找最少的人,输出left;第二题要找最大的分段值,输出left
所以通常找最少输出满足solve时和变动值相反的量;找最大输出满足solve时和变动量相同的量
但具体还是得根据题意进行判断喔,免得栽在奇葩题目里哈哈哈哈哈

#2020寒假集训#二分入门(Binary Search)代码笔记相关推荐

  1. 二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现

    问题背景 今年的实习生招聘考试,我出了一道二分查找(Binary Search)的题目.题目大意如下: 给定一个升序排列的自然数数组,数组中包含重复数字,例如:[1,2,2,3,4,4,4,5,6,7 ...

  2. 数据结构与算法(八)二分搜索树(Binary Search Tree)

    本文主要包括以下内容: 二分搜索树的基本概念 二分搜索树的基本操作 1. 插入 2. 删除 3. 查询 实现二分搜索树 二分搜索树的不足 二分搜索树的基本概念 二分搜索树(英语:Binary Sear ...

  3. 八、二分查找(Binary Search)

    一.概述 二分查找(Binary Search,也称折半查找)--针对有序数据集合的查找算法 1.基本思想 类似分治思想,每次都通过跟区间的中间元素进行对比,将代查找的区间缩小为之前的一半,直到找到要 ...

  4. Leetcode中几道二分查找(Binary Search)的算法题总结

    二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列.二分查找法的时间复杂度是对数级别的,O(lo ...

  5. ABAP性能优化之使用二分查找(Binary Search)选项

    READ命令使用顺序查找数据表,这会降低处理速度.取而代之,使用binary search的附加命令,可以使用二分查找算法,可以帮助加快内表查找速度. 在使用binary search之前 必须首先将 ...

  6. SAPABAP性能优化技巧—使用二分查找(Binary Search)选项

    READ命令使用顺序查找数据表,这会降低处理速度.取而代之,使用binary search的附加命令,可以使用二分查找算法,可以帮助加快内表查找速度. 在使用binary search之前必须首先将内 ...

  7. 二分查找 Binary Search

    明确循环不变量:变量的值可能在变化,但是它的含义是不变的 https://baike.baidu.com/item/循环不变量/8353186?fr=aladdin 如何写出正确的程序? 明确变量的含 ...

  8. #2020寒假集训#树形基础入门(Tree)代码笔记

    树的基础定义 [无根树]一棵没有固定根结点的树(树→图:无向图) (补充一)无根树可以任意指定一个节点作为根节点,将根节点"提起",其它节点自然"垂下" [无根 ...

  9. 2019年寒假集训-二分专题

    问题 A: [递归]二分查找 题目描述 用递归算法实现二分查找,即:有n个已经从小到大排序好的数据(不重复),从键盘输入一个数X,用对半查找方法,判断它是否在这n个数中. 输入 第一行,正整数n,N& ...

最新文章

  1. 中文详解phpmailer所有对象和属性
  2. Redis详解(一)------ redis的简介与安装
  3. Redis Cluster 高可用方案
  4. Linux服务器运行sh文件提示权限不够解决方法?飞腾服务器Permission denied问题授权方法
  5. linux centos7 安装redis
  6. PCRE接口pcre_fullinfo混合子模式调用结果
  7. 题目1362:左旋转字符串(Move!Move!!Move!!!)
  8. Windows开发的内功和招式
  9. 消息称苹果、Epic开庭时间从2021年7月提前至5月份
  10. PHP 获取访问来源
  11. POJ 3421 X-factor Chains
  12. 《网络基础》- 第3集-IP地址、子网掩码和路由器的作用
  13. linux定时备份文件到指定文件夹,Linux定时备份数据库到指定邮箱的方法
  14. 7-2 秋天的第一杯奶茶 (5 分)
  15. 让计算机提速的方法,如何让电脑提速(让电脑提速的方法步骤详解 )
  16. chatGPT发送图片的方法
  17. 【BP数据预测】基于matlab斑点鬣狗算法优化BP神经网络数据预测【含Matlab 219期】
  18. oracle 主键、唯一键值、唯一索引关系
  19. 会签 数据库表设计_关于OA流程相关数据表的设计
  20. FPGA并行编程-以HLS实现数字信号处理

热门文章

  1. 【openwrt】使用4G模块 移远EC20/25(2)pppd拨号与配置
  2. XenApp 7.6:如何启用客户端IME,启用客户端输入法
  3. SQL Server的备份
  4. 天行健,君子以自强不息!
  5. Linux脚本定时清理日志任务
  6. CSDN博客文章必须要登录才能查看解决办法
  7. 手机数控模拟器安卓版_数控机床模拟器手机版下载-数控机床模拟器(CNC Simulator)安卓版v1.1.4 - 比克尔下载...
  8. 响应式精美列表商城发卡源码
  9. 南京邮电大学网络信息安全——网络数据包捕获WireShark(实验一)
  10. 关于springboot项目连接oracle数据库报错 ORA01017的改正