从有序数组中查找某个值
Lower_bound
package 二分搜索;
import java.util.Scanner;
public class 有序数据中查找某个值LOWERBOUND {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
}
int k=sc.nextInt();
//初始化解的存在范围
int lb=-1;
int ub=n;
//重复循环,知道解的存在范围不大于1
while(ub-lb>1){
int mid=(lb+ub)/2;
if(a[mid]>=k){
//如果mid满足条件,则解的存在范围变为(1b,mid)
ub=mid;
}else{
//如果不满足条件(mid,ub)
lb=mid;
}
}
//此时lb+1=ub
System.out.println(ub);
}
}
假设一个解并判断是否可行
Cable master
二分搜索的模型试图解决这个问题
令:
求满足C(X)条件的最大值X,在区间初始化时,只需要使用充分大的数INF(>MAX)作为上界即可
lb=0;
ub=INF
现在的问题就是是否可以高效的判断C(X),由于长度LI的绳最多可以切除floor(Li,x)段长度位x绳子,因此
它可以在O(N)的时间内被判断出来
package 二分搜索;
import java.util.Scanner;
public class Cablemaster {
private static int n;
private static double[] a;
private static int k;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
a = new double[n];
for(int i=0;i<n;i++){
a[i]=sc.nextDouble();
}
//初始化解的范围
double lb=0,ub=Integer.MAX_VALUE;
//重复循环,知道解的范围足够小
for(int i=0;i<100;i++){
double mid=(lb+ub)/2;
if(C(mid))
lb=mid;
else
ub=mid;
}
System.out.printf("%.2f",ub);
}
//判断是否满足条件
private static boolean C(double x) {
// TODO Auto-generated method stub
int num=0;
for(int i=0;i<n;i++){
num+=(int)(a[i]/x);
}
return num>=k;
}
}
如果在求解最大化或最小化问题中,能够比较简单地判断条件是否满足,那么使用二分搜索法就可以很好的解决问题
专栏,二分搜索的结束判定
在输出小数的问题中,一般都会制定允许的误差范围或是制定输出小数点后面的位数。因此在使用二分搜索法时,有必要设置合理的结束条件来满足精度的要求。在上面的程序中,我们指定了循环次数作为终止条件。1次循环可以把区间的范围缩小一半,100次的循环则可以达到10-30的精度范围,基本上是没有问题的。除此之外,也可以把终止条件设为像(ub-lb)>EPS这样,指定一个区间的大小。在这种情况下,如果EPS取得太小了,就有可会因为浮点小数精度的与您导致陷入死循环,请千万小心
最大化最小化
Aggressive cows
类似的最大化最小值或者最小化最大值的问题,通常用二分搜索法就可以很好的解决。
package 二分搜索;
import java.util.Arrays;
import java.util.Scanner;
public class 最大化最小值 {
private static int n;
private static int m;
private static int[] x;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
x = new int[n];
for(int i=0;i<n;i++)
x[i]=sc.nextInt();
//最开始时对x数组排序
Arrays.sort(x);
//初始化解的存在范围
int lb=0,ub=Integer.MAX_VALUE;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(C(mid))
lb=mid;
else
ub=mid;
}
}
private static boolean C(int d) {
// TODO Auto-generated method stub
int last=0;
for(int i=1;i<m;i++){
int crt=last+1;
while(crt<n&&x[crt]-x[last]<d)
crt++;
if(crt==n)
return false;
last=crt;
}
return true;
}
}
最大化平均值
package 二分搜索;
import java.util.Arrays;
import java.util.Scanner;
public class 最大化最小值 {
private static int n;
private static int m;
private static int[] x;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
x = new int[n];
for(int i=0;i<n;i++)
x[i]=sc.nextInt();
//最开始时对x数组排序
Arrays.sort(x);
//初始化解的存在范围
int lb=0,ub=Integer.MAX_VALUE;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(C(mid))
lb=mid;
else
ub=mid;
}
}
private static boolean C(int d) {
// TODO Auto-generated method stub
int last=0;
for(int i=1;i<m;i++){
int crt=last+1;
while(crt<n&&x[crt]-x[last]<d)
crt++;
if(crt==n)
return false;
last=crt;
}
return true;
}
}