二分搜索
来源:互联网 发布:如何设置监控网络连接 编辑:程序博客网 时间:2024/06/06 05:02
对《挑战程序设计竞赛》的一个记录
第三章 出类拔萃——中级篇
3.1 二分搜索
(1) 从有序数组中查找某个值
这个是最常见的二分搜索,在这就不多说了
(2)假定一个解并判断是否可行
之前不知道原来二分有那么多用处,往下看
poj 1064
有N条绳子,他们的长度分别为Li,如果从他们中切割出K条相同的绳子的话,这K条绳子每段最长能有多长?答案保留到小数点后2位。
已知:
1≤N≤10000
1≤K≤10000
1≤Li≤100000
sample input
N = 4
K = 11
L = {8.02,7.43,4.57,5.39}
sample output
2.00(每条绳子可以得到4条,3条,2条,2条,总计11条)
二分搜索模型的建立,令条件C(x):=可以得到K条长度为x的绳子
我们要二分的是绳子的长度,已知最小长度为0(l = 0),最大长度为最长绳子的长度(r = INF),当二分到某个值时,如果能得到的绳子数>K,表明当前值小了,还可以切更大的
这题要注意的是最后输出时,长度不要四舍五入后的值,例如2,005我要的是2.00而不是2.01,如果直接printf("%.2lf",ans),会自动四舍五入的。
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <string>#define sf scanf#define pf printf#define eps 1e-10using namespace std;const int Maxn = 10010;double len[Maxn];int n,k;int getnum(double mid){ int num = 0; for(int i = 0;i < n;i ++) num += (int)(len[i]/mid); return num;}double solve(double r){ double l = 0; while(l - r < -eps) { double mid = (l + r) / 2; if(getnum(mid) < k) r = mid; else l = mid; } return r;}int main(){ while(~sf("%d%d",&n,&k)) { double Max = 0; for(int i = 0;i < n;i ++) { sf("%lf",&len[i]); if(len[i] > Max) Max = len[i]; } double ans = solve(Max); pf("%.2f\n",floor(ans * 100) / 100); } return 0;}
(3) 最大化最小值
poj 2456 Aggressive cows
农夫约翰搭了一间有N见牛舍的小屋。牛舍排在一条线上,第i号牛舍在xi的位置,但是他的M头牛对小屋很不满意,因此经常相互攻击,约翰为了防止牛之间互相伤害,因此决定把每头牛放在离其他牛尽可能远的牛舍,也就是最大化最近的两头牛之间的距离。
已知:
2≤N≤100000
2≤M≤N
0≤Xi≤10^9
sample input
N = 5
M = 3
x = {1,2,8,4,9}
sample output
3(在位置1,4,8的牛舍中放入三头牛)
这道题其实跟上一题其实很像,我们可以定义C(d):=可以安排牛的位置使得任意牛的间距不小于d
首先按牛舍的距离排序
二分到某个d值后,从第一个牛舍开始放牛,找到一个牛舍使得它与之前放牛的牛舍距离≥d,再放入一头牛,依次计算,得到一共能放k头牛,如果k>M,说明二分的d值太小,还可以继续扩大。
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <string>#define sf scanf#define pf printfusing namespace std;const int Maxn = 100010;int n,k;int x[Maxn];int getnum(int mid){ int num = 1; int f = x[0]; for(int i = 1;i < n;i ++) { if(x[i] - f >= mid) { num ++; f = x[i]; } } return num;}int solve(int l,int r){ while(l <= r) { int mid = (l + r) / 2; if(getnum(mid) < k) r = mid - 1; else l = mid + 1; } return r;}int main(){ while(~sf("%d%d",&n,&k)) { for(int i = 0;i < n;i ++) sf("%d",&x[i]); sort(x,x + n); pf("%d\n",solve(0,x[n - 1] - x[0])); } return 0;}
(4) 最大化平均值
有n个物品的重量和价值分别问wi和vi,从中选出k个物品使得单位重量的价值最大
已知:
1≤k≤n≤10^5
1≤wi,vi≤10^6
sample input
n = 3
k = 2
{w,v} = {{2,2},{5,3},{2,1}}
sample output
0.75(如果选择0号和2号,平均价值为(2 + 1)/(2 + 2) = 0.75)
这题的想法比前两个难一点,首先想到的就是对平均值进行二分枚举,但是枚举到值后,怎么去确定到底是由哪些物品构成了这个平均值。
换个思路,如果是按贪心的方法,把物品按单位价值进行排序,从大到小进行贪心地进行选取,但是这个方法的得到的结果是5/7 = 0.714,那到底该如何求解呢?
还是二分,我们定义条件C(x):=可以选择使得单位重量的价值不小于x。我们选择某些物品的集合S,使得其单位重量的价值为
因此判断是否存在S满足下面的条件:
即
因此对vi-x*wi进行贪心的选取就好了,按vi-x*wi从大到小排,如果前k个值使得不等式成立,则这个集合S是符合条件的,可以继续扩大x的范围。
poj 3111 代码如下:
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <string>#define sf scanf#define pf printf#define eps 1e-7using namespace std;const int Maxn = 100010;int n,k;int ans[Maxn];struct node{double w,v;double perval;int p;};node jew[Maxn];double cmp(node x,node y){return x.perval > y.perval;}int getnum(double mid){for(int i = 0;i < n;i ++)jew[i].perval = jew[i].v - jew[i].w * mid;sort(jew,jew + n,cmp);double num = 0;for(int i = 0;i < k;i ++)num += jew[i].perval;return num >= 0;}void solve(double l,double r){while(l - r < -eps){double mid = (l + r) / 2;if(getnum(mid)){l = mid;for(int i = 0;i < k;i ++)ans[i] = jew[i].p;}else r = mid;}}int main(){while(~sf("%d%d",&n,&k)){double Max = 0;for(int i = 0;i < n;i ++){sf("%lf%lf",&jew[i].v,&jew[i].w);jew[i].p = i + 1;if(jew[i].v / jew[i].w > Max)Max = jew[i].v / jew[i].w;ans[i] = i + 1;}solve(0,Max);sort(ans,ans + k);pf("%d",ans[0]);for(int i = 1;i < k;i ++)pf(" %d",ans[i]);pf("\n");}return 0;}
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 实现一个函数来调整该数组中数字的顺序实例
- Win7 64位VS2010搭建OpenCV2.4.9
- django models进行数据库增删查改
- halcon学习笔记——(4)HDevelop language(结构语句)
- 编程实现木马的ActiveX启动和注入IE的启动方式
- 二分搜索
- iOS概念入门学习-Foundation-protocol
- sdf夺回gsdf;gklsdf;一夺杯需要
- C++ 通过null指针调用成员函数 正常
- Tempter of the Bone -- BFS 回溯 剪枝
- equals()和==的用法及区别
- wince6.0 vs2005下不能断点调试的问题
- Colour Hash (Uva 704 双向bfs)
- IOS项目发布时如何填写Itunes Connect的app信息