二分----整数二分,浮点数二分

目录

整数二分

猜数字游戏

​编辑二分原理

例题:整数二分模版讲解

找到有序区间中=x最左边的数字的位置。

​编辑找到有序区间中= α 最右边的数字的位置。

找到有序区间中>=x 第一个数字的位置。

找到有序区间中>x 第一个数字的位置。

例题:分巧克力

浮点数二分

数的M次方根


整数二分


猜数字游戏

Random random = new Random();
//生成 1 到 100 之间的随机数
int targetNumber = random.nextInt(100)+ 1;
// 初始化猜测次数
int guesscount = 0;
System.out.println("欢迎来到猜数字游戏!");
system.out. println("我已经想好了一个 1 到 100 之间的数字。试着猜猜看吧!");
//游戏主循环
while (true){
System.out.print("请输入你的猜测:");
int userGuess = in.nextInt();
guesscount+;//记录猜测次数
//判断用户的猜测
if(userGuess < targetNumber){
System.out.println("你猜的数字太小了。");
} else if (userGuess > targetNumber){
System.out.println("你猜的数字太大了。");
} else {
//用户猜中了
System.out.println("恭喜你,猜对了!你总共猜了"+ guesscount +"次。");
break;

}

}


二分原理

二分法,也叫二分查找法,是一种用于在有序数组或列表中快速查找目标元素的位置的算法。它的核心思想是通过每次将查找范围折半,逐步缩小查找范围,直到找到目标元素或确认目标不存在。复杂度是 log2n
二分查找步骤:
1.确定初始查找区间为[l,r],其中 l是左边界,r是右边界。
2.计算中间位置mid,并判断目标值是否在区间[l,mid]还是[mid+1,r]中。
3.根据判断结果缩小查找范围,并重复该过程,直到找到目标值或查找区间为空。


例题:整数二分模版讲解

找到有序区间中=x最左边的数字的位置。

 static int getL(int a[], int l, int r, int x){
            while (l < r){
            int mid = l + r>> 1;
            if(x <= a[mid]){
            r= mid;
            } else {
            l = mid + l;}}
            if (a[l]!= x) return -1;
            return l;}


找到有序区间中= α 最右边的数字的位置。


static int getR(int a[], int l, int r, int x) {
while (l <r){
int mid = l + r + 1 >> 1;
if(x< a[mid]){
r= mid - 1;
} else {
l = mid;

}}
if(a[l]!= x) return -1;
return 1;}

找到有序区间中>=x 第一个数字的位置。

static int lower_bound(int a[], int l, int r, int x) {
    if (x > a[r]) return -1;
    while (l <r){
    int mid = l + r >> 1;
    if(x<= a[mid]){
    r = mid;
    } else {
    l = mid + 1;

    }}
    return 1;}

找到有序区间中>x 第一个数字的位置。

  static int upper_bound(int a[], int l, int r, int x) {
        if (x >= a[r]) return -1;
        while (l < r){
        int mid = l + r >> 1;
        if (x < a[mid]){
        r = mid;
        } else {
        l = mid + 1;

        }}
        return 1;

        }


例题:分巧克力

给定n 个边长为 w× h的巧克力,你需要固定一个边长 a,使得巧克力可以划分成至少k块 ax a 的小巧克力。问 α最大可以是多少。
暴力做法为枚举巧克力的边长,看分出来的数量是不是满足k块。

 static boolean check(int x){
        long ans=0;
        for(int i=1;i<=n;i++){
        ans=ans+(h[i]/x)*(w[i]/x);
        if(ans>=k) return true;
        }
        return false;

        }
        for(int i=1;i<=100000;i++){
        if(!check(i)){
        return i-1;}}
    


可以看出随着巧克力边长的变小,巧克力分出来的数量越多,因此是一个递减函数。具有单调性。

 int l=1,r=100000;
    while(l<r){
    int mid=(l+r+1)/2;
    if(check(mid)){
    l=mid;
    }else{
    r=mid-1;
    }

    }
    out.println(l);


    static boolean check(int x){
    long ans=0;
    for(int i=1;i<=n;i++){
    ans=ans+(h[i]/x)*(w[i]/x);
    if(ans>=k) return true;

    }
    return false;

    }

import java.util.Scanner;

//1:无需package
//2: 类名必须Main, 不可修改

public class lll {
    static int n,k;
    static int H[],W[];
    static boolean check(int x) {//最大值
        int res=0;
        for(int i=1;i<=n;i++) {
            res+=(H[i]/x)*(W[i]/x);
            if(res>=k)return true;
        }
        
        return false;
    }
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        n=in.nextInt();
        k=in.nextInt();
        H=new int[n+10];
        W=new int[n+10];
        for(int i=1;i<=n;i++) {
            H[i]=in.nextInt();
            W[i]=in.nextInt();
        }
        int l=1,r=100000;//权值不能太大
        while(l<r) {
            int mid=(l+r+1)>>1;
        if(check(mid)) {
            l=mid;
        }else {
            r=mid-1;
        }
        }
        System.out.println(l);
    }
    }

浮点数二分

数的M次方根


给定一个整数 N,你需要求解 N 的 M 次方根,保留 7 位小数。
暴力思路是从 0 开始枚举,每次加 10^-7,时间复杂度太高了。
for(double i=0;i<=N;i=i+0.0000001){
double res=1;
for(int j=1;j<=M;j++){
res=res*i;

}
if(res==N){
out.println(res);
break;

}}


我们可以二分 M 次方根,二分左端点为 0,右端点为 N。
二分的终止条件我们要从 l< r变成l+ eps < r。eps 是一个误差小数,一般小数位数是 7,我们就写
10^-9次方,如果是 6,就写 10^-8。
double eps=1e-9;
double l=0,r=N;
while(l+eps<r){
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main{
    static double eps=1e-9;
    static double M;
    static double N;
    static boolean check(double x){
        double res=1;
        for(int i=1;i<=M;i++){
        res=res*x;}
        return res>=N ;
    }
    public static void main(String[] args) {
         N=in.nextDouble();
        M=in.nextDouble();
        double l=1,r=N;
        while(l+eps<r){
            double mid=(l+r)/2;
            if(check(mid)){
                r=mid;
            }else{
                l=mid;
            }
        }
        out.printf("%.7f",l);
        out.flush();
    }
    static FastReader in=new FastReader();
    static PrintWriter out=new PrintWriter(System.out);
    static class FastReader{
        static BufferedReader BR;
        static StringTokenizer ST;
        FastReader(){
            BR=new BufferedReader(new InputStreamReader(System.in));
        }
        String next(){
            String str="";
            while(ST==null||!ST.hasMoreElements()){
                try{str=BR.readLine();
            }catch(IOException e){
                throw new RuntimeException(e);}
                ST=new StringTokenizer(str);
            }
            return ST.nextToken();
        }
        int nextInt(){
            return Integer.parseInt(next());
        }
        long nextLong(){
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值