• Codeforces Gym 101505C : Cable Connection (计算几何)


    题目链接

    题意:给出第一象限的N个点,存在一直线x/a+y/b=1(a>0,y>0)使得所有点都在这条直线下面,求 min{sqrt(a^2+b^2)}

    显然,这样的直线必然经过这N个点中的某一个(可用反证法证得),所以先对只有一个点的情况进行分析。

    当只有一个点P(x0,y0)时,易得

    此时设t=a/b,可知,a^2+b^2可写成两个凹函数相加的形式,故可用三分法求解。

    所以N个点的情况就可解了。容易想到,只需要考虑凸包上位于右上侧的点(满足该点的左上方右下方都有点),那么该点就有成为“关键的点”的可能,至于三分时的自变量的范围,就根据这个点的前后两个点来得到即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    const double eps=1e-9;
    const double inf=2e6;
    int dcmp(double x)
    {
        if(fabs(x)<eps) return 0;
        else return x<0? -1:1;
    }
    
    struct Point
    {
        double x,y;
        Point(double x_=0,double y_=0)
        {
            x=x_,y=y_;
        }
        Point operator -(const Point& rhs)
        {
            return Point(x-rhs.x,y-rhs.y);
        }
        bool operator<(const Point& rhs)const
        {
            return x<rhs.x||x==rhs.x&&y<rhs.y;
        }
    };
    typedef Point Vector;
    double Cross(Vector A,Vector B)
    {
        return A.x*B.y-A.y*B.x;
    }
    double Area2(Point A,Point B,Point C)
    {
        return Cross(B-A,C-A);
    }
    int ConvexHull(Point *p,int n,Point *ch)
    {
        sort(p,p+n);
        int m=0;
        for(int i=0; i<n; i++)
        {
            while(m>1&&dcmp(Area2(ch[m-2],ch[m-1],p[i]))<=0) --m;
            ch[m++]=p[i];
        }
        int k=m;
        for(int i=n-2; i>=0; --i)
        {
            while(m>k&&dcmp(Area2(ch[m-2],ch[m-1],p[i]))<=0) --m;
            ch[m++]=p[i];
        }
        return n>1? m-1:m;
    }
    //=============================================================
    const int maxn=1e6+5;
    Point p[maxn],ch[maxn];
    double k[maxn];
    
    double xielv(Point A,Point B)
    {
        if(dcmp(A.x-B.x)==0) return -inf;
        else return (A.y-B.y)/(A.x-B.x);
    }
    double cal(Point P,double P_k)    
    {
        double a=P.x-P.y/P_k;
        double b=P.y-P.x*P_k;
        return sqrt(a*a+b*b);
    }
    double sanfen(Point P,double k1,double k2)
    {
        double l=k1,r=k2;
        while(r-l>eps)
        {
            double mid=(l+r)/2;
            double f1=cal(P,mid);
            double midmid=(mid+r)/2;
            double f2=cal(P,midmid);
            if(f1<f2)    r=midmid;
            else    l=mid;
        }
        return cal(P,l);
    }
    
    int main()
    {
        int n,m;
        while(~scanf("%d",&n))
        {
            double ans=inf;
            double maxx=0,maxy=0;
            for(int i=0; i<n; i++)    //读点
            {
                scanf("%lf%lf",&p[i].x,&p[i].y);
                maxx=max(maxx,p[i].x),maxy=max(maxy,p[i].y);
            }
            p[n++]=Point(maxx,0),p[n++]=Point(0,maxy);    //加点,便于处理 
            m=ConvexHull(p,n,ch);    //求凸包
            for(int i=0; i<m; i++) k[i]=xielv(ch[i],ch[(i+1)%m]); //求斜率
            for(int i=0; i<m; i++)
                if(ch[i].x>=ch[(i+1)%m].x&&ch[i].y<=ch[(i+1)%m].y && ch[(i+1)%m].x>=ch[(i+2)%m].x&&ch[(i+1)%m].y<=ch[(i+2)%m].y)
                    ans=min(ans,sanfen(ch[(i+1)%m],k[i],k[(i+1)%m]));
            printf("%.3lf
    ",ans+eps);
        }
    }
  • 相关阅读:
    mysql中bigint、int、mediumint、smallint 和 tinyint的取值范围
    centos6.5下安装samba服务器与配置
    centos 6.5 安装图形界面【转】
    Linux 下添加用户,修改权限
    Linux下自动调整时间和时区与Internet时间同步
    C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)
    Unity脚步之NetworkBehaviour下前进、后退、左右转向的简单移动
    Token 在 Ajax 请求头中,服务端过滤器跨域问题
    【游戏】【暗黑2】重置属性点和技能点
    ASCII
  • 原文地址:https://www.cnblogs.com/Just--Do--It/p/7668228.html
Copyright © 2020-2023  润新知