poj 1064二分+精度(重要的是细节问题!)1064

以前大体了解二分的思想,只知道大大简化时间复杂度,但没有真正手敲,于是发现很多细节问题:

①二分大体是确定要查找的对象!(一般是长度等有序数据!)→将被查找数据写入数组(要排序!二分查找的对象核心是单调!单调!单调!或者说有序)初始化左右端点(确定上下界)→限定查找范围(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);//题目要求的是保留小数点而不是四舍五入,而且取得是右端点(最大值)
}

猜你喜欢

转载自blog.csdn.net/zjyang12345/article/details/80242885