二分搜索:从有序数组中查找某个值、假设一个解并判断是否可行、最大化平均值

从有序数组中查找某个值

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;
	}

}

发布了342 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44522477/article/details/105257138