算法笔记二分查找题目

解决的问题

  • 寻找有序序列中第一个满足条件的元素的位置

注意点

  • 当二分上界超过int型数据范围的一半,那么当欲查询元素在序列较靠后的位置时。mid=(left+right)/2可能溢出,此时一般使用mid=left+(right-left)/2避免溢出。

题目

如何在一个严格递增序列A中找出给定的数X

//如何在一个严格递增序列A中找出给定的数X
int binarySearch(int A[], int left,int right,int X)
{
	//初始left=0 right=n-1
	while (left <= right)
	{
		int mid = left + (right - left) / 2;
		if (A[mid] == X) 
		{
			return mid;
		}
		else if (A[mid] > X)//X应在mid的左侧
		{
			right = mid - 1;
		}
		else {//X应在mid的右侧
			left = mid + 1;
		}
	}
	//在合法区间中没有找到,返回-1
	return -1;
}

如果递增序列A中的元素可能重复,那么如何对给定的欲查询元素x,求出序列中第一个大于等于x的元素的位置L以及第一个大于x的元素位置R。这样元素x在序列中的存在区间就是左闭右开区间[L,R)

计算根号2在误差为10-5的近似值

#define ens 1e-5
#include<algorithm>
#include<iostream>
using namespace std;
double f(double x)
{
	return x * x;
}
//计算根号2在误差为10-5的近似值
//可以将题意变为在[1,2]之间寻找误差在这个范围之间的近似值,使用x^2逼近
double binary(double left,double right,int M)
{
	//取[left,right]中间值,如果(mid+-end)^2>2=>mid>根号2 left=mid 
	while (right-left > ens)
	{
		double mid = left + (right - left) / 2;
		if (f(mid)>=M)//说明在[left,mid]
		{
			right = mid;
		}
		else 
		{
			left = mid;
		}
	}
	return left;
	
}
int main()
{
	double res = binary(1, 2, 2);
	cout << res << endl;
}

给定一个定义在[L,R]上的单调函数f(x),求方程f(x)=0的根

#define eps 1e-5
//给定一个定义在[L,R]上的单调函数f(x),求方程f(x)=0的根
double f(double x)
{
	return x * x - 2;
}
double getF(int L,int R)
{
        int mid = L + (R - L) / 2;
	while (R - L > eps) 
	{
		
		if (f(mid) > 0)
		{
			R = mid;
		}
		else if (f(mid) == 0)
		{
			return mid;
		}
		else 
		{
			L = mid;
		}
	}
	return mid;
}

装水问题:有一个侧面看去时半圆的出水装置,该半圆的半径为R要求往里面装入高度为h的水,使其在侧面看去的面积与半圆面积的比例恰好为r。现在给定R和r求高度h

#include<cmath>
#include<cstdio>
#define eps 1e-5
#define PI acos(-1.0)
double f(double h, double R)
{
	double alpha = 2 * acos((R - h) / R);
	double L = 2 * sqrt(R * R - (R - h) * (R - h));
	double S1 = alpha * R * R  - L * (R - h);
	double S2 = PI * R * R;
	return S1 / S2;
}
//因为f随着h的增大而增大
double solve(double r,double R)
{
	int left = 0, right = R;
	int mid;
	while (right - left > eps)
	{
		mid = left + (right - left) / 2;
		if (f(mid, R) > r)
		{
			right = mid;
		}
		else {
			left = mid;
		}
	}
	return mid;
}

木棒切割问题:给出N根木棒,长度均已知,现在希望通过切割它们来得到至少K段长度相等的木棒(长度必须是整数)。问这些长度相等的木棒最长能有多长。

#include<iostream>
using namespace std;
int mubangs[] = { 10,24,15 };
int n=3;
int f(int length)
{
	int num = 0;
	for (int i = 0; i < n; i++)
	{
		int t = mubangs[i] / length;
		num += t;
	}
	return num;
}
int getMaxL(int K)
{
	int length = 1;
	int num = f(length);
	while (num>= K)
	{
		length++;
		num = f(length);
	}
	return length-1;
}

给出N个线段的长度,试将它们头尾相接(顺序任意)地组合成一个凸多边形,使得该凸多边形的外接圆(即能使凸多边形的所有顶点都在圆周上的圆)的半径最大。

//外接圆圆心与每个线段顶点连接后会有一个圆心角,如果圆心在凸多边形内部,则所有圆心角之和应该为2π。如果圆心在凸多边形外部,则最大的圆心角等于其他圆心角之和。
//如果半径比rmax大,那么这些线段的圆心角之和sum<2∗π,线段没法首尾相连的在外接圆上,半径应变小。
//如果半径比rmax小,那么这些线段的圆心角之和sum>2∗π,这时构成的外接圆不是半径最大的外接圆,半径应变大。
//给出N根木棒,长度均已知,
//现在希望通过切割它们来得到至少K段长度相等的木棒(长度必须是整数)。
#include<cmath>
#include<iostream>
#define eps 1e-5
#define PI acos(-1.0)
//求圆心角之和
int edges[];
double f(double r,int n)
{
	double sum = 0;
	for (int i = 0; i < n; i++)
	{
		double alpha = 2*asin(edges[i] / 2 / r);
		sum += alpha;
	}
	return sum;
}
int main()
{
    int N;//边数
    scanf("%d", &N);//输入边数

    double sum;//圆心角之和
    double maxAngle = 0.0;//最长边对应的圆心角
    double maxEdge = 0.0;//最长边


    //初始化edges
    for (int i = 0; i < N; i++)
    {
        scanf("%lf", &edges[i]);
        if (edges[i] > maxEdge)
            maxEdge = edges[i];//保存最大边
    }
    //取最长边作为直径
    sum = f(maxEdge / 2, N);
    if (abs(sum - 2 * PI) < eps)
    {
        printf("外接圆的最大半径是最大边的一半:%.2f", maxEdge / 2);
        return 0;
    }
    //半径大于最大边的一半(即斜边大于直角边)
    double left = maxEdge / 2, right = 10000, mid,other;
    while (right - left > eps)
    {
        mid = left + (right - left) / 2;
        maxAngle = asin(maxEdge / 2 / mid) * 2;//求出最大边对应的圆心角
        sum = f(mid, N);
        other = sum - maxAngle;
        //如果除去最大圆心角的其他圆心角之和小于π,说明圆心在多边形外面
        if (other < PI)
        {
            sum = other + 2 * PI - maxAngle;
            if (sum < 2 * PI)
                left = mid;
            else
                right = mid;
        }
        //圆心在多边形里面
        else
        {
            if (sum > 2 * PI)
                left = mid;
            else
                right = mid;
        }
        printf("外接圆的最大半径是:%.2f", mid);
        return 0;
    }
}

参考:https://blog.csdn.net/flashmsn/article/details/94642687
https://www.cnblogs.com/transmigration-zhou/p/12275464.html

posted @ 2021-08-09 15:10  小帆敲代码  阅读(34)  评论(0编辑  收藏  举报