牛客寒假算法基础集训营5 牛牛战队的训练地(三分)

题目:https://ac.nowcoder.com/acm/contest/3006/B
参考题解:https://ac.nowcoder.com/acm/problem/blogs/201956
三分法参考博客:https://blog.csdn.net/beiyouyu/article/details/7875480?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

这个题目的方法就是对答案三分,接下来详细说一下三分法
我们都知道二分可以求具有单调性的函数中的某个值。
三分法主要用于解决寻找单峰函数的极值,而这个题目我们分析一下范围可以大致得出随着x增大,最大距离是先增后减的。
所以三分的具体方法就是我们要将分为两半,然后在对其中的一变进行再分两半,总体就是2:1:1的形式。这里,我们用m表示一半,用mm表示一半的一半。要求最小值就只需要每次将边界移到大的那一边
那么还有一个问题,查找答案应该循环多少次?如何将它表示出来?

有两种方法:1.直接用for循环一定的次数。
这里用的是100次。因为每一次循环,都将剩余的区间进行了又一次的三分,这都是2的负次幂级的下降。所以,2的-100次幂再乘以区间长度的值应该是足够精确的了。
2.while循环
while (l + EPS < r)
这里的EPS是一个无限小的数,这个很好理解就不再多说。
代码如下:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f;
const int N=100005;
using namespace std;
typedef long long ll;
struct node{
    
    
    int x,y;
}a[N];
int n;
double maxn;
double check(double c){
    
    
    maxn=0.0;
    for(int i=1;i<=n;i++){
    
    
        double sum=a[i].y*a[i].y+(a[i].x-c)*(a[i].x-c);
        maxn=max(maxn,sum);
    }
    return maxn;
}

void slove(double l,double r){
    
    
    for(int i=1;i<=100;i++){
    
    
        double m=l+(r-l)/2;
        double mm=l+(m-l)/2;
        if(check(mm)>check(m))
            l=mm;
        else
            r=m;
    }
}
int main ()
{
    
    
    //freopen("D:\\input.txt", "r", stdin);
    //freopen("D:\\output.txt", "w", stdout);
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d %d",&a[i].x,&a[i].y);
    slove(-10000,10000);
    double ans=sqrt(maxn);
    cout<<ans<<endl;
	return 0;
}


猜你喜欢

转载自blog.csdn.net/u011612364/article/details/104758220