隐形的翅膀
背景
小杉终于进入了天堂。他看到每个人都带着一双隐形翅膀,他也想要。(小杉是怎么看到的?……)
天使告诉小杉,每只翅膀都有长度,两只翅膀的长度之比越接近黄金分割比例,就越完美。
现在天使给了小杉N只翅膀,小杉想挑出一对最完美的。
格式
输入格式
每组测试数据的
第一行有一个数N(2<=N<=30000)
第二行有N个不超过1e5的正整数,表示N只翅膀的长度。
20%的数据N<=100
对每组测试数据输出两个整数,表示小杉挑选出来的一对翅膀。
注意,比较短的在前,如果有多对翅膀的完美程度一样,请输出最小的一对。
样例1
样例输入1
4
2 3 4 6
样例输出1
2
3
限制
每个测试点1s
你可以认为黄金分割比就是0.6180339887498949
题目分析
分类:二分查找这题直接用双重循环,每次计算分割比,若等于黄金分割比则输出,时间复杂度O(n^2),会超时。
这里要,先将数据进行排序,用二分查找的方式,计算num[i]/num[mid]最接近黄金分割比的下标。但是这里用二分查找到的下标,有可能找到的并不是最接近的。
举个例子,6 7 8 9 12对应的下标分别为0 1 2 3 4
mid=(0+4)/2=2
6/8=0.75>0.6180339887498949 l=mid+1
mid=(3+4)/2=3
6/9=0.66666667>0.6180339887498949 l=mid+1
mid=(4+4)/2=4
6/12=0.5
此时取到的下标为4,但是明显可以看出下标为3,即9的时候更接近黄金分割比。
这是由于在二分的过程中不是正好相等的情况,而差值则会导致有可能前面一个更接近黄金分割比,有可能后面一个更接近黄金分割比,在查找的过程由于大于或者小于而跳过了。所以要对查找的的mid与mid-1和mid+1都进行比较,找到最接近黄金分割比的。
完整代码如下:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 30000
double num[maxn];
#define result 0.6180339887498949
int main(){
int N;
int i,l,r,suit,mid,s1,s2;
double k,a,b,c,min;
cin>>N;
for(i=0;i<N;i++){
cin>>num[i];
}
sort(num,num+N);
min=1;
for(i=0;i<N-1;i++){
l=i;
r=N-1;
while(l<=r){
mid=(l+r)/2;
if(num[i]/num[mid]<=result){
r=mid-1;
}else{
l=mid+1;
}
}
a=fabs(num[i]/num[mid-1]-result); //注意这里要用绝对值
b=fabs(num[i]/num[mid]-result);
c=fabs(num[i]/num[mid+1]-result);
if(a<=b){
if(a<=c){
suit=mid-1;
}else{
suit=mid+1;
}
}else{
if(b<=c){
suit=mid;
}else{
suit=mid+1;
}
}
if(num[i]/num[suit]==result){
s2=suit;
s1=i;
break;
}
if(min>fabs(num[i]/num[suit]-result)){
min=fabs(num[i]/num[suit]-result);
s2=suit;
s1=i;
}
}
cout<<num[s1]<<endl<<num[s2]<<endl;
return 0;
}