二分和三分笔记

二分查找算法

简单定义:

在一个单调有序的集合中查找元素,每次将集合分为左右两部分 ,判断解在哪个部分中并调整集合上下界,重复直到找到目标元素,是一种分治的算法。

时间复杂度:最坏O(logn)

简单示例:

输入两个整数m(m>0),n(n>0),再输入m个数,判断这m个数是否存在数n若有则输出YES,没有则输出NO,比如判断数组a[11]={5,13,19,21,37,56,64,75,80,88,92}中是否有数"21",其过程如下图:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e3+10;
int main()
{
    int a[maxn],n,mid,t=0,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    int left=0;
    int right=n-1;
    while(left<right)
    {
        mid=(left+right)/2;
        if(a[mid]>m)
            right=mid-1;    //注意这个操作很关键
        else if(a[mid]<m)
                left=mid+1;   //注意这个操作很关键
             else
             {
                 t=1;
                 break;
             }
    }
    if(t)
      printf("YES\n");
    else
        printf("NO\n");
}

题目

F - Cable master

为了购买网络电缆,评审委员会已经联系了一个本地网络解决方案提供商,他们要求为他们销售指定长度的电缆。评审委员会希望电缆尽可能长,以使参赛者尽可能地远离对方。 
公司的电缆主管被指派负责这项工作。他知道每根电缆的长度可达一厘米,他可以以厘米的精度切割它们,告诉它们必须切割的碎片的长度。然而,这一次,长度不知道,电缆主人是完全困惑。 
你要帮助电缆主,通过编写一个程序,确定电缆的最大长度,可以从股票中的电缆切割,以获得指定的件数。

Input

The first line of the input file contains two integer numb ers N and K, separated by a space. N (1 = N = 10000) is the number of cables in the stock, and K (1 = K = 10000) is the number of requested pieces. The first line is followed by N lines with one number per line, that specify the length of each cable in the stock in meters. All cables are at least 1 meter and at most 100 kilometers in length. All lengths in the input file are written with a centimeter precision, with exactly two digits after a decimal point.

Output

Write to the output file the maximal length (in meters) of the pieces that Cable Master may cut from the cables in the stock to get the requested number of pieces. The number must be written with a centimeter precision, with exactly two digits after a decimal point. 
If it is not possible to cut the requested number of pieces each one being at least one centimeter long, then the output file must contain the single number "0.00" (without quotes).

Sample Input

4 11
8.02
7.43
4.57
5.39

Sample Output

2.00

我的代码有问题,没检查出来┭┮﹏┭┮,下面是别人的代码:https://blog.csdn.net/zhangxiaoduoduo/article/details/79950054

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
double a[100005];
using namespace std;
bool ck(double m,int n,int k)
{
    int sum=0;
    for(int i=0;i<n;i++)
        sum+=(int)(a[i]/m);
    return sum>=k;
}
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
	{
        for(int i=0;i<n;i++)
            scanf("%lf",&a[i]);
        double l=0,r=100005,mid=0;
        int i=1000;
        while(i--)
		{
            mid = (l+r)/2;
            if(ck(mid,n,k))
                l = mid;
            else
                r = mid;
        }
        printf("%0.2lf\n",(floor(r*100))/100);
    }
}

三分

问题

H - Light Bulb

Compared to wildleopard's wealthiness, his brother mildleopard is rather poor. His house is narrow and he has only one light bulb in his house. Every night, he is wandering in his incommodious house, thinking of how to earn more money. One day, he found that the length of his shadow was changing from time to time while walking between the light bulb and the wall of his house. A sudden thought ran through his mind and he wanted to know the maximum length of his shadow.

 

Input

The first line of the input contains an integer T (T <= 100), indicating the number of cases.

Each test case contains three real numbers Hh and D in one line. H is the height of the light bulb while h is the height of mildleopard. D is distance between the light bulb and the wall. All numbers are in range from 10-2 to 103, both inclusive, and H - h >= 10-2.

Output

For each test case, output the maximum length of mildleopard's shadow in one line, accurate up to three decimal places..

Sample Input

3
2 1 0.5
2 0.5 3
4 3 4

Sample Output

1.000
0.750
4.000

我的思路:先写出人与灯的水平距离x和影长l的函数l(x)(我的函数,没有化简,直接写出来的),再由函数知晓可将此函数分段为两段:

l(x)=\begin{cases} & \text (h/(H-h))*x ,0\leqslant x\leqslant D/(H/(H-h)) \\ & \text (D-x+(((H/(H-h))*x-D)/((H/(H-h))*x))*H, x>D/(H/(H-h))\end{cases}函数第一段是单调的一次函数,可以用二分也可用三分来求值域中的最大值(我用的三分来求的),第二段则需要用三分来求最大值,将两段的最大值lm1和lm2分别求出,再比较得出更大的值即为所求。

#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<algorithm>
double H,h,D;
double l(double x)   //x为人与灯的水平距离
{
	if((H/(H-h))*x>D)  
	   return D-x+(((H/(H-h))*x-D)/((H/(H-h))*x))*H;
	else if((H/(H-h))*x<=D)  
			return (h/(H-h))*x;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int a=1000;
		int b=1000;
		scanf("%lf%lf%lf",&H,&h,&D);  
		double m11,m12,m21,m22,lm1,lm2,low1=0,high1=D-(h/H)*D,low2=high1,high2=D;
		while(low1+0.00000001<high1)  //在此情况时可以直接用二分来计算,因为此时函数l(x)为单调递增的单调函数,我这里用的是三分的方法
		{
			m11=low1+(high1-low1)/3.0;
			m12=low1+((high1-low1)/3.0)*2.0;
			if(l(m11)<l(m12))
			  low1=m11+1e-10;   //个人觉得此处是坑点如果没有1e-10这题就没法过,可能在没有时,计算精度不高吧,下面同理要注意加一下,如果有哪位大佬知道其中的原因,感谢留言o(* ̄3 ̄)o 
			else 
			  high1=m12-1e-10;
		}
		while(low2+0.00000001<high2)  
		{
			m21=low2+(high2-low2)/3.0;
			m22=low2+((high2-low2)/3.0)*2.0;
			if(l(m21)<l(m22))
			  low2=m21+1e-10;
			else 
			  high2=m22-1e-10;
		}
		if(l(m11)>l(m12))
		   lm1=l(m11);
		else
		   lm1=l(m12);
		if(l(m21)>l(m22))
		   lm2=l(m21);
		else
		   lm2=l(m22);
		if(lm1>lm2)
		   printf("%0.3lf\n",lm1);
		else
		   printf("%0.3lf\n",lm2);
	}                                                                                          
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值