二分法(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条绳子每条最长是多少. 二分答案,尤其注意精度问题.我觉 ...
随机推荐
- Qt:Qt自适应高分辨率屏幕
现在的电脑分辨率越来越高,DPI也越来越大,使用Qt创建出来的界面,在小分辨率电脑上显示的很好,但是在大分辨率电脑上显示异常,感觉边框被压缩了,看起来很不协调. 从Qt 5.6 还是从Qt 5.14 ...
- centos-stream-9 centos9 配置国内yum源 阿里云源
源配置 tips: yum配置文件路径 /etc/yum.repos.d/centos.repo 1.备份源配置 [Very Important!] mv /etc/yum.repos.d/cento ...
- 【01】微服务(Microservice)是什么?为什么会出现微服务?
微服务(Microservice)虽然是当下刚兴起的比较流行的新名词,但本质上来说,微服务并非什么新的概念. 实际上,很多 SOA(面向服务的架构)实施成熟度比较好的企业,已经在使用和实施微服务了.只 ...
- Kotlin泛型的高级特性
Kotlin中是可以将内联函数中的泛型进行实化的. 那么具体该怎么写才能将泛型实化呢?首先,该函数必须是内联函数才行,也就是要用inline 关键字来修饰该函数.其次,在声明泛型的地方必须加上reif ...
- Flink Standalone集群部署
Flink Standalone模式部署集群是最简单的一种部署方式,不依赖于其他的组件,另外还支持YARN/Mesos/Docker等模式下的部署,这里使用的flink版本为最新的稳定版1.9.1版本 ...
- 力扣176(MySQL)-第二高的薪水(中等)
题目: id 是这个表的主键.表的每一行包含员工的工资信息. 编写一个 SQL 查询,获取并返回 Employee 表中第二高的薪水 .如果不存在第二高的薪水,查询应该返回 null . 查询结果如下 ...
- 力扣357(java)-统计各位数字都不同的数字个数(中等)
题目: 给你一个整数 n ,统计并返回各位数字都不同的数字 x 的个数,其中 0 <= x < 10n . 示例 1: 输入:n = 2输出:91解释:答案应为除去 11.22.33.44 ...
- 全面提升易用性:OpenClusterManagement 0.7 版本发布
简介:千呼万唤始出来,三月末 OpenClusterManagement 社区正式发布了 v0.7 版本.在新的版本有一系列新的功能特性欢迎感兴趣的读者体验探索,同时在这个版本中社区维护者对目前已有 ...
- 重温设计模式之 Factory
简介: 创建型模式的核心干将,工厂.简单工厂.抽象工厂,还记得清么,一文回顾和对比下. 作者 | 弥高来源 | 阿里技术公众号 前言 创建型模式的核心干将,工厂.简单工厂.抽象工厂,还记得清么,一文回 ...
- [Mobi] MacOS 安装设置 ADB (Android Dedug Bridge)
adb (Android Dedug Bridge) 是 Google 提供的一个工具,用于调试 Android 应用程序和系统的各个部分. 在 MacOS 平台,调试安卓应用 首先需要安装 Andr ...