二分法(POJ-1064与POJ-2456)
二分查找,简而言之就是在一个有序的序列中找一个元素,因为这些元素已经有序,所以每次都将要找的数跟待寻找序列的中间元素比较,如果要找的数大于中间元素,说明接下来只需要在该序列的右半边中找,所以可以不用管左半边了,这样每次都排除一半的元素直到最后找到要找的元素。我们可以用两个变量代表待寻找序列的最左端索引(l)和最右端索引(r),然后两个变量的中间元素是mid,再经过比较之后考虑将r移动到mid处成为下一次寻找的新的r值,还是将l值移动到mid+1处成为下一次寻找的l值。
代码模板:
while(l < r){
int mid = l + (r-l) / 2; //不直接用(l+r)/2是为了防止l+r的时候溢出
if(judge(mid)) l = mid+1; //judge函数是自己定义的,判断要找的数在序列的哪半边的
else r = mid;
}
因为这样找的情况之下
需要注意一个细节的关于边界的问题:假设要在100个排好序的数中找到某数(这个数的索引最后我们得知是8),最后这个while循环只会等到 l 和 r 两个数相等的时候才会停止,当循环停止的时候 ,并不知道上一个循环的lr分别是7和8,然后是l被赋值成为mid+1得到8的,还是l与r原本为8和9,然后r被赋值成为mid的,所以这个时候需要在最后再判断一下,因为循环结束的时候l和r已经相等了,所以他们指向的位置如果不是要找的数,那么l-1(或者说r-1)处的元素才是我们要找的元素
下面给出二分法的例题
POJ 1046
https://vjudge.net/problem/POJ-1064
最最简单的二分查找
题意大概是有N根木棍,然后每一根都有着自己的长度,现在要求截断这些木棍,给出K根长度相等的木棍,问最长能截成多长(不能拼接)。
那就直接用二分法做,从0到最长木棍的长度这样一直往最合适的点逼近即可,然后每次有了猜测的长度mid之后,就遍历所有木棍,然后将每一根木棍都截出尽可能多小木棍,也就是直接 / mid ,然后加到总数中啦。
但是要注意一个特殊的地方,就是除零的时候可能出错(在下方代码中也标出来了)
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100500;
int N,K,k,ma = 0;
double b,ans;
int c[maxn];
bool judge(int mid, int k){
int sum = 0;
if(mid == 0) return 0; //这里如果不直接返回0的话可能在下下行 /mid的时候发生除零错
for(int i=0;i<N;i++){
sum += c[i] / mid;
if(sum >= k) return 1;
}
return 0;
}
void binsearch(int l,int r,int k){
while(l<r){
int mid = (r-l)/2+l;
if(judge(mid,k)) l = mid+1;
else r = mid;
}
if(judge(l,k)) ans = double(l) / 100.0;
else ans = double(l-1) / 100.0;
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
#endif
scanf("%d%d",&N,&K);
for(int i=0;i<N;i++){
scanf("%lf",&b);
c[i] = int(b * 100);
if(c[i] > ma) ma = c[i];
}
sort(c,c+N,greater<int>());
binsearch(0,c[0],K);
if(ans < 0.01) ans = 0.00;
printf("%.2f\n",ans);
return 0;
}
稍难一点的题是 POJ-2456
https://vjudge.net/problem/POJ-2456
题意比较简单,就是有N个点在数轴上排成一横排,你要从中取C个点使得这C个点中任意两个点之间的最短距离最大。首先看到任意两个点之间的最短距离,那这个距离肯定从相邻i啷个点之间的距离中来选出,因为如果a,b,c三个点依次从左到右排开,也就是说ab两个点相邻而ac两个点不相邻,那么ac之间的距离肯定大于ab。
然后这个题就是我们说到的最大化最小值的问题,因为它要满足两个要求(又要是所有间距中最小,又要是所有分配方案中最大)而贪心基本上除了一些特殊的处理(比如poj2010等等)只能满足往一个条件去贪,这样就比较难做。
但是二分就可以解决这个问题,毕竟是要找一个数嘛,那么我们其实还是一个一个地去尝试,只不过二分了之后可以每次试玩排除一半的数,这样就降低了复杂度。
基本思路就是先取l为最小距离(一般就是0啦),然后再取任意两点之间距离的最大值(也就是第一个点和最后一个点之间的距离),然后我们的所有的值就在这中间找啦。每次判断中间值是否符合要求,因为我们要找的是尽量大,所以一旦符合要求,我们就删掉左半边序列,往右半边去找,反之才往左半边去找,那么怎么才能够判断是否符合要求呢?
既然这个时候中间值mid是我们猜测的一个解,那么首先它需要满足它是所有间隔中的最小值,我们就所以任意间隔都要比他大,我们从最左边的点开始,依次遍历所有点,然后每当凑到距离>= mid了之后,就表示我们可以选这个遍历了的点,然后继续往下走,如果凑到了C个点,就说明这个mid是符合要求的,(反之如果所有点都遍历完了,还没有凑到C个点,就说明该mid不符合要求,不是我们要的解),如果符合要求了,那么再到它的右边去找,(上述操作就是代码中的judge过程,也就是判断中间这个数能否满足我们的基础要求(即所有间距中的最小值),二分的过程就是找这些值中的最大)
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 100150;
int N,C;
int a[maxn];
bool judge(int x){
int cur = a[0],num = 1;
for(int i=1;i<N;i++){
if(a[i] - cur >= x) {
num++;
cur = a[i];
}
if(num >= C) return true;
}
return false;
}
void solve(){
int l = 0,r = a[N-1] - a[0];
while(l < r){
int mid = l + (r-l) / 2; //不直接用(l+r)/2是为了防止l+r的时候溢出
if(judge(mid)) l = mid+1;
else r = mid;
}
if(judge(r)) cout<<r<<endl;
else cout<<l-1<<endl;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%d%d",&N,&C);
for(int i=0;i<N;i++){
scanf("%d",&a[i]);
}
sort(a,a+N);
solve();
return 0;
}
二分法(POJ-1064与POJ-2456)的更多相关文章
- POJ 1064 Cable master(二分查找+精度)(神坑题)
POJ 1064 Cable master 一开始把 int C(double x) 里面写成了 int C(int x) ,莫名奇妙竟然过了样例,交了以后直接就wa. 后来发现又把二分查找的判断条 ...
- poj 1064 Cable master 判断一个解是否可行 浮点数二分
poj 1064 Cable master 判断一个解是否可行 浮点数二分 题目链接: http://poj.org/problem?id=1064 思路: 二分答案,floor函数防止四舍五入 代码 ...
- POJ 1064 1759 3484 3061 (二分搜索)
POJ 1064 题意 有N条绳子,它们长度分别为Li.如果从它们中切割出K条长度相同的绳子的话,这K条绳子每条最长能有多长?答案保留小数点后2位. 思路 二分搜索.这里要注意精度问题,代码中有详细说 ...
- 二分搜索 POJ 1064 Cable master
题目传送门 /* 题意:n条绳子问切割k条长度相等的最长长度 二分搜索:搜索长度,判断能否有k条长度相等的绳子 */ #include <cstdio> #include <algo ...
- POJ 1201 Intervals || POJ 1716 Integer Intervals 差分约束
POJ 1201 http://poj.org/problem?id=1201 题目大意: 有一个序列,题目用n个整数组合 [ai,bi,ci]来描述它,[ai,bi,ci]表示在该序列中处于[ai, ...
- POJ 1064 Cable master (二分法+精度控制)
Cable master Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 65358 Accepted: 13453 De ...
- 第三章 poj 1064——关于带精度的二分法
/* 题意:给定n个实数l[i],给定一个k 问:求最大的ans,使得sum l[i]/ans i=1 to n >=k,且ans最大*/ #include <iostream> # ...
- POJ 1064 (二分)
题目链接: http://poj.org/problem?id=1064 题目大意:一堆棍子可以截取,问要求最后给出K根等长棍子,求每根棍子的最大长度.保留2位小数.如果小于0.01,则输出0.00 ...
- poj 1064 (二分+控制精度) && hdu 1551
链接:http://poj.org/problem?id=1064 Cable master Time Limit: 1000MS Memory Limit: 10000K Total Submi ...
- POJ 1064 Cable master (二分答案)
题目链接:http://poj.org/problem?id=1064 有n条绳子,长度分别是Li.问你要是从中切出m条长度相同的绳子,问你这m条绳子每条最长是多少. 二分答案,尤其注意精度问题.我觉 ...
随机推荐
- OpenHarmony 社区运营报告(2023 年 10 月)
● 截至2023年10月,OpenHarmony社区共有51家共建单位,累计超过6200名贡献者产生24.2万多个PR,2.3万多个Star,6.1万多个Fork,59个SIG. ● OpenHa ...
- 使用Apache POI和Jsoup将Word文档转换为HTML
简介 在现代办公环境中,Word文档和HTML页面都是常见的信息表达方式.有时,我们需要将Word文档转换为HTML格式,以便在网页上展示或进行进一步的处理.本文将介绍如何使用Apache POI库和 ...
- js调用摄像头,实现简单的视频展台软件
参考文档: web api:https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices codeantenna:https://code ...
- Unity-PC 端调用SpVoice语音 (文字转语音)
第一步引用文件 在VS当中 点击项目->添加引用-> 搜索Microsoft Speech Objecet Library 然后选中前面的白色方块点击确定就行了 插入之后 你的引用库中会多 ...
- 如何在HarmonyOS对数据库进行备份,恢复与加密
数据库备份与恢复 场景介绍 当应用在处理一项重要的操作,显然是不能被打断的.例如:写入多个表关联的事务.此时,每个表的写入都是单独的,但是表与表之间的事务关联性不能被分割. 如果操作的过程中出现问题, ...
- GAN的一些问题
GAN为什么难以训练? 大多深度模型的训练都使用优化算法寻找损失函数比较低的值.优化算法通常是个可靠的"下山"过程.生成对抗神经网络要求双方在博弈的过程中达到势均力敌(均衡).每个 ...
- 局部区块多个报表 TAB 页切换及局部区块的参数查询
在企业的业务系统中,如何从纷繁复杂的数据中抽丝剥茧看到关键数据信息呢?一个重要的途径就是将企业和各部门运营中关键的 KPI 集中在一起显示,同时尽量省去在企业的各个业务系统中分别查找数据. 下面是我近 ...
- nginx重新整理——————编译nginx[二]
前言 简单编译一下nginx. 正文 为什么我们要去编译nginx. 系统安装,比如yum安装,会把nginx 模块直接编译进来. 这意味着,我们无法使用第三方的包.如果我们需要使用第三方包,那么需要 ...
- node 父子进程传递对象
背景 node的父子进程中可以传递这是肯定的,但是传递对象,这是一个稀奇的地方. code 发送 server 对象 sendHandle 参数可用于将一个 TCP server 对象句柄传给子进程, ...
- xilinx的serdes接收时钟坑
ilinx的7 series fpga transceivers wizard用于自定义的serdes编码. 要选择多个serdes端口,如下图,点击对应的名称,然后右边选择use该设备就可以. 生成 ...