以前大体了解二分的思想,只知道大大简化时间复杂度,但没有真正手敲,于是发现很多细节问题:
①二分大体是确定要查找的对象!(一般是长度等有序数据!)→将被查找数据写入数组(要排序!二分查找的对象核心是单调!单调!单调!或者说有序)→初始化左右端点(确定上下界)→限定查找范围(while的条件)→
if-else(查找满足的条件)(一般另写一个函数)
{
端点移动(一般left=mid+1,right=mid-1)
}
→选值(二分最后取左端点,还是右端点,还是这一个区间,要看题目);
需要思考的:
查谁
单调(有些并不明显,比如最大化最小值问题,即搜索的距离越大,分组数越小,距离和分组存在单调关系)
上下界 poj 3273 https://blog.csdn.net/zjyang12345/article/details/80272253
判条件 poj 3104 和最大化平均值问题
①Judge函数怎么写? (难的用到贪心算法,或数学公式设变量找关系)
②看每个小区间取不取得到端点,poj1064向下取整、2456、3258最大化最小值区间左闭右开,取不到最值;poj3273最小化最大值区间左开右闭,取得到最值。
取端点 poj2456等 最大值最小化的问题,一般整数类型习惯【L,R)即取L。
附:while和left、right赋值是套路,看代码学习。
精度方面:
①精度控制大体范围eps,但有时for循环50-100次就足够了。
②四舍五入和保留小数之间的差异。
③强制类型转换注意加括号的范围。
#include<iostream>
#include<iomanip>#include<stdio.h>
#include<cmath>
using namespace std;
double L[10010];
int Judge(double mid,int N)
{
int sum=0;
for(int i=0;i<N;i++)
{
sum+=L[i]/mid;//不小心将L[i]强制转换成int,WA到死
}
//cout<<sum<<endl;
return sum;
}
int main()
{
int N,K;
scanf("%d%d", &N, &K);
double r=1e5+1;
double l=0;
double mid;
for(int i=0;i<N;i++)
{
scanf("%lf", &L[i]);
}
while(r-l>=1e-10)//精度必须控制得当,但1e-15的话容易陷入死循环
//for(int i=0;i<100;i++) //挑战上面的方法
{
mid=(l+r)/2;
// cout<<"mid="<<mid<<endl;
if(Judge(mid,N)>=K)
l=mid;
else
r=mid;
}
//mid=3.567;
int m=(int)(r*100);
double p=(double)m/100.0;
// cout<<fixed<<setprecision(2)<<r<<endl;//这是四舍五入操作
printf("%.2f\n", p);//题目要求的是保留小数点而不是四舍五入,而且取得是右端点(最大值)
}