ACM零起点2017-7-27(查找算法之------尺取法、二分法、三分法)
来源:互联网 发布:淘宝网外国小女孩模特 编辑:程序博客网 时间:2024/06/05 09:13
第一波:尺取法
应用于有这么一类问题:需要在给的一组数据中找到不大于某一个上限的“最优连续子序列”
例题 Subsequence POJ - 3061
题目来源:https://vjudge.net/problem/POJ-3061
210 155 1 3 5 10 7 4 9 2 85 111 2 3 4 5
23
本题应用尺取法思路:
分析:首先,序列都是正数,如果一个区间其和大于等于S了,那么不需要在向后推进右端点了,因为其和也肯定大于等于S但长度更长,所以,当区间和小于S时右端点向右移动,和大于等于S时,左端点向右移动以进一步找到最短的区间,如果右端点移动到区间末尾其和还不大于等于S,结束区间的枚举。
针对样例1,尺取法的具体过程如下:
AC代码:
1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233
#include<cstdio>#include<algorithm>using namespace std;const int maxn=100005;long long a[maxn];int main(){ int t; scanf("%d",&t); while(t--) { int n; long long sum=0,s; int ans=maxn; scanf("%d%I64d",&n,&s); for(int i=0;i<n;i++) scanf("%I64d",&a[i]); int st=0,en=0; while(1) { while(en<n && sum<s)sum+=a[en++]; if(sum<s)break; ans=min(ans,en-st); sum-=a[st++]; } if(ans==maxn)ans=0; printf("%d\n",ans); } return 0;}
第二波:二分法
下面包含了STL中的binary_search(),upper_bound(),lower_bound()
1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
#include<iostream>#include<algorithm>using namespace std;//二分查找,区间左闭右开,针对有序列int bin_search(int a[],int left,int right,int v){ int mid; while(left<right) { mid=left+(right-left)/2; if(v==a[mid])return mid; else if(v<a[mid])right=mid; else left=mid+1; } return -1;}//利用上面的二分查找算法,寻找下界int low_bound(int a[],int left,int right,int v){ int mid; while(left<right) { mid=left+(right-left)/2; if(v<=a[mid])right=mid; else left=mid+1; } return left;}//利用上面的二分查找算法,寻找上界int up_bound(int a[],int left,int right,int v){ int mid; while(left<right) { mid=left+(right-left)/2; if(v>=a[mid])left=mid+1; else right=mid; } return left;}int main(){ int a[5]; int v;//要查找的数 for(int i=0;i<5;i++) a[i]=i+10; bool success=binary_search(a+0,a+5,12);//库函数,查找是否成功,返回bool值 int location=bin_search(a,0,5,12);//返回查找到元素的位置,如果没有查到,则返回-1 cout<<"12 "<<(success?"found":"not found"); if(success)//也可以写成:if(location>=0) cout<<" ,location:"<<location<<endl; cout<<"lower_bound:"<<*lower_bound(a,a+5,12)<<endl;//针对非递减序列,返回第一个大于等于某个数的值 cout<<"upper_bound:"<<*upper_bound(a,a+5,12)<<endl;//针对非递减序列,返回第一个大于某个数的值 cout<<"low_bound:"<<low_bound(a,0,5,12)<<endl;//返回的是对应数组中的下标 cout<<"up_bound:"<<up_bound(a,0,5,12)<<endl;//返回的是对应数组中的下标 return 0;}
第三波:三分法
三分法应用于单峰凸函数,下面举一个例子(借用:http://blog.csdn.net/pi9nc/article/details/9666627)
如图所示,已知左右端点L、R,要求找到白点的位置。
思路:通过不断缩小 [L,R] 的范围,无限逼近白点。
做法:先取 [L,R] 的中点 mid,再取 [mid,R] 的中点 mmid,通过比较 f(mid) 与 f(mmid) 的大小来缩小范围。
当最后 L=R-1 时,再比较下这两个点的值,我们就找到了答案。
1、当 f(mid) > f(mmid) 的时候,我们可以断定 mmid 一定在白点的右边。
反证法:假设 mmid 在白点的左边,则 mid 也一定在白点的左边,又由 f(mid) > f(mmid) 可推出 mmid < mid,与已知矛盾,故假设不成立。
所以,此时可以将 R = mmid 来缩小范围。
2、当 f(mid) < f(mmid) 的时候,我们可以断定 mid 一定在白点的左边。
反证法:假设 mid 在白点的右边,则 mmid 也一定在白点的右边,又由 f(mid) < f(mmid) 可推出 mid > mmid,与已知矛盾,故假设不成立。
同理,此时可以将 L = mid 来缩小范围。
伪代码实现:
- int SanFen(int l,int r) //找凸点
- {
- while(l < r-1)
- {
- int mid = (l+r)/2;
- int mmid = (mid+r)/2;
- if( f(mid) > f(mmid) )
- r = mmid;
- else
- l = mid;
- }
- return f(l) > f(r) ? l : r;
- }
【题目实战】
开始每个人都在一条数轴上的某个位置上,位置大于等于1,都是整数,每个人有个最大移动速度,在数轴上某个点集合,可以花费最短的时间,求出这个最短的时间。
AC代码:
1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142
#include<cstdio>#include<algorithm>#include<cmath>#define INF 0x3f3f3f3fusing namespace std;const double eps=0.000001;const int maxn=60010;double a[maxn],b[maxn];int n;double check(double x){ double ans=0; for(int i=0;i<n;i++) ans=max(ans,fabs(x-a[i])/b[i]); return ans;}int main(){ double mmin=1.0*INF,mmax=-1.0*INF; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%lf",&a[i]); mmin=min(mmin,a[i]); mmax=max(mmax,a[i]); } for(int i=0;i<n;i++) scanf("%lf",&b[i]); double l=mmin,r=mmax; while(l+eps<r) { double mid=(l+r)/2; double mmid=(mid+r)/2; if(check(mid)>check(mmid))l=mid; else r=mmid; } printf("%.12lf\n",check(r)); return 0;}
- ACM零起点2017-7-27(查找算法之------尺取法、二分法、三分法)
- ACM零起点2017-7-28(贪心算法)
- ACM零起点2017-7-24(刷题)
- ACM零起点2017-7-25(随机数产生方法)
- ACM零起点2017-7-26(全排列问题)
- ACM零起点2017-7-27(C++中string的基本用法)
- ACM算法:尺取法
- ACM零起点2017-7-25(C++ STL in ACM)
- 算法之二分法查找
- 查找算法之二分法查找
- ACM零起点2017-7-25(sort用重载运算符对结构体排序)
- ACM零起点2017-7-25(二叉搜索树概念)
- 基本算法之二分法查找
- 排序算法之 二分法查找
- 算法学习之二分法查找
- Java算法之二分法查找
- day_6-acm 二分查找+尺取法
- acm练习 零起点学算法78——牛牛 2017 02 24
- HTML学习笔记
- [2] UI原型设计工具Pencil Project 学习系列----- 入门
- jvm优化
- 初步认识CSS
- 1019. 数字黑洞 ( )
- ACM零起点2017-7-27(查找算法之------尺取法、二分法、三分法)
- 直接用cellpadding和cellspacing布局
- spring学习笔记5
- [大数据]-Elasticsearch5.3.1 IK分词,同义词/联想搜索设置
- hdu1465(错排)
- matlab字符串的操作及正则表达式regexp
- 20个非常有用的Java程序片段
- 源码中throw new RuntimeException("Stub!");的含义
- 点击按钮(button)打开新窗口(window)的几种情况