三分算法


牛牛战队的比赛地

题目描述

由于牛牛战队经常要外出比赛,因此在全国各地建立了很多训练基地,每一个基地都有一个坐标(x,y)(x,y)(x,y)。

这周末,牛牛队又要出去比赛了,各个比赛的赛点都在xxx轴上。牛牛战队为了方便比赛,想找一个到达训练基地最大距离最小的地方作为比赛地。

这个问题对于牛牛战队太简单了,它就交给了你,你来帮他算一下~

输入描述:

 

输入数据第一行包含一个整数N(1≤N≤100 000)N(1 \leq N \leq 100\,000)N(1≤N≤100000),表示牛牛战队训练基地的数量。

接下来NNN行,每行包括222个整数x,y(−10 000≤x,y≤10 000)x,y(-10\,000 \leq x,y \leq 10\,000)x,y(−10000≤x,y≤10000),表示每一个训练基地的坐标。

输出描述:

 

输出一个小数,表示选择的比赛地距离各训练基地最大距离的最小值。

如果你的答案是aaa,标准答案是bbb,当∣a−b∣max(1,∣b∣)≤10−4\frac{|a-b|}{max(1,|b|)}\leq 10^{-4}max(1,∣b∣)∣a−b∣​≤10−4时,你的答案将被判定为正确。

示例1

输入

复制3 0 0 2 0 0 2

3
0 0
2 0
0 2

输出

复制2

2

说明

当在(0,0)(0,0)比赛时,到三个训练基地的最大距离是22。可以证明这是最小值。
来着 儒生雄才1 聚聚发布的std:
#include <bits/stdc++.h>
using namespace std;
 
struct p{
    int x,y;
}a[100005];
int n;
double check(double x)
{
    double max=0;
    for (int i=1;i<=n;i++)
    {
        double tmp=sqrt(a[i].y*a[i].y+(a[i].x-x)*(a[i].x-x));
        if (tmp>max) max=tmp;
    }
    return max;
}
double tsearch(double left,double right){
    int i;
    double mid,midmid;
    for(i=0;i<100;i++){
        mid=left+(right-left)/2;
        midmid=mid+(right-mid)/2;
        if(check(mid)>check(midmid)) //极大值求法
            left=mid;
        else
            right=midmid;
    }
    return mid;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d%d",&a[i].x,&a[i].y);
    double max=tsearch(-10000,10000);
    printf("%.4lf\n",check(max));
    return 0;
}

#10013. 「一本通 1.2 例 3」曲线

破题:公式似乎也可以?三分点,逐渐逼近最值点

#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <functional>
/// #include <unordered_map>
/// #include <multimap>
/// #include <multiset>
#include <map>
#include <stack>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <utility>
#include <cstring>
using namespace std;
#define PI acos(-1)
#define TLE std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define pb push_back
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
const ll mod = 1000000007 ;
const int mxn = 1e5+10 ;
ll prime[mxn],isprime[mxn],bit[mxn],a[mxn],b[mxn],c[mxn];
int n,m,t,u,w,l,r,k,x;
string str , s1  ,s2 , s3;
struct node {double x,y,z;}poi[mxn];
double check(double x)
{
    double res = -1e9 ;
    for(int i=1;i<=n;i++)
        res = fmax( res , poi[i].x*x*x+poi[i].y*x+poi[i].z ) ;
    return res ;
}

double slove(double l,double r)
{
    double mid , midmid;
    while(r-l>1e-11)
    {
        mid = l + (r-l)/3;
        midmid = r - (r-l)/3;
        if(check(mid) > check(midmid))
            l = mid ;
        else
            r = midmid ;
    }
    return mid ;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n) ;
        for (int i=1; i<=n; i++)
            scanf("%lf %lf %lf",&poi[i].x,&poi[i].y,&poi[i].z);
        double ans = slove(0,1000);
        printf("%.4lf\n",check(ans));
    }
}

#10016. 「一本通 1.2 练习 3」灯泡

破题:梯形相似推公式,三分位置,三分的原因的如果影子刚好到达墙角,那么,向前一步时水平影子减少的长度和竖直影子长度的增加,那个相对较大

#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <functional>
/// #include <unordered_map>
/// #include <multimap>
/// #include <multiset>
#include <map>
#include <stack>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <utility>
#include <cstring>
using namespace std;
#define PI acos(-1)
#define TLE std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define pb push_back
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
const ll mod = 1000000007 ;
const int mxn = 1e5+10 ;
ll prime[mxn],isprime[mxn],bit[mxn],a[mxn],b[mxn],c[mxn];
int n,m,t,u,w,l,r,k,x;
string str , s1  ,s2 , s3;
double H,D,h ;
double check(double x){return x + (D*h - x*H)/(D-x);}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lf %lf %lf",&H,&h,&D) ;
        double l = 0 , r = h/H*D ;
        while(r-l>1e-5)
        {
            double mid = l+(r-l)/3 ,
                   midmid = r-(r-l)/3;
            if(check(mid) > check(midmid))
                r = midmid ;
            else
                l = mid ;
        }
        printf("%.3lf\n",check(l));
    }
}

1857: [Scoi2010]传送带

Description

在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段。两条传送带分别为线段AB和线段CD。lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R。现在lxhgww想从A点走到D点,他想知道最少需要走多长时间

Input

输入数据第一行是4个整数,表示A和B的坐标,分别为Ax,Ay,Bx,By 第二行是4个整数,表示C和D的坐标,分别为Cx,Cy,Dx,Dy 第三行是3个整数,分别是P,Q,R

Output

输出数据为一行,表示lxhgww从A点走到D点的最短时间,保留到小数点后2位

Sample Input

0 0 0 100
100 0 100 100
2 2 1

 

Sample Output

136.60

HINT

对于100%的数据,1<= Ax,Ay,Bx,By,Cx,Cy,Dx,Dy<=1000
1<=P,Q,R<=10

破题:所有叙述都和图结合,对于AB上的任意一点F,都可以找到从F到达CD的时间最短路径,也就是EF,那么,AF-FE-ED就是我们要求的时间最短路径,那么,如果枚举AB上点的话,TLE预定,那么,可以这样想,如果是平行的话,EF路径时间一定,找AB,CD速度最大的就可以;如果不平行的话,我们可以假设E点是确定的点,那么,E到AB的距离图像就是一个ou(打不出来,求教怎么打ou字)函数图像,那么最低点就是EF的最短距离,这样的话,我们就三分AB,midl,midr,那么再三分CD,找一个点,就算time-dis并最小时间记录位置,直到三分AB退出,那么,再对CD进行一次三分,最后time就是最短的。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <functional>
/// #include <unordered_map>
/// #include <multimap>
/// #include <multiset>
#include <map>
#include <stack>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <utility>
#include <cstring>
using namespace std;
#define PI acos(-1)
#define TLE std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define pb push_back
#define ll long long
#define pii pair<int,int>
#define eps 1e-3
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
const ll mod = 1000000007 ;
const int mxn = 1e5+10 ;
ll prime[mxn],isprime[mxn],bit[mxn],a[mxn],b[mxn],c[mxn];
string str , s1  ,s2 , s3;
int ax,ay,bx,by,cx,cy,dx,dy,p,q,r;
double dis_time(double x1,double y1 , double x2 ,double y2) {return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
double check(double x , double y)
{
    double lx = cx , ly = cy , rx = dx , ry = dy ;
    while(fabs(rx-lx)>eps || fabs(ry-ly)>eps)
    {
        double midlx = lx+(rx-lx)/3 , midly = ly + (ry - ly)/3 ;
        double midrx = rx-(rx-lx)/3 , midry = ry - (ry - ly)/3 ;
        double time_l = dis_time(ax,ay,x,y)/p + dis_time(x,y,midlx,midly)/r+dis_time(midlx,midly,dx,dy)/q ;
        double time_r = dis_time(ax,ay,x,y)/p + dis_time(x,y,midrx,midry)/r+dis_time(midrx,midry,dx,dy)/q ;
        if(time_l > time_r)
            lx = midlx , ly = midly ;
        else
            rx = midrx , ry = midry ;
    }
    return dis_time(ax,ay,x,y)/p + dis_time(x,y,lx,ly)/r+dis_time(lx,ly,dx,dy)/q ;
}
int main()
{
    cin>>ax>>ay>>bx>>by>>cx>>cy>>dx>>dy>>p>>q>>r;
    double lx = ax , ly = ay , rx = bx , ry = by ;
    while(fabs(rx-lx)>eps || fabs(ry-ly)>eps)
    {
        double midlx = lx+(rx-lx)/3 , midly = ly + (ry - ly)/3 ;
        double midrx = rx-(rx-lx)/3 , midry = ry - (ry - ly)/3 ;
        double time_l = check(midlx,midly);
        double time_r = check(midrx,midry);
        if(time_l > time_r)
            lx = midlx , ly = midly ;
        else
            rx = midrx , ry = midry ;
    }
    printf("%.2lf\n",check(lx,ly));
}
发布了102 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/m0_43382549/article/details/104308047
今日推荐