zoukankan      html  css  js  c++  java
  • 1082. 【GDOI2005】选址

    Description

    很久以前,在世界的某处有一个形状为凸多边形的小岛,岛上的居民们决定建一个祭坛,居民们任务祭坛的位置离岛的顶点处越远越好。 你的任务是求凸多边形内一点,使其与各顶点的距离中最短的距离最远,点在边上也可以。 这样的点可能有多个,你只需输出这些点与各顶点的最短距离。

    Solution

    先考虑最后的答案在多边形内部。

    可以证明,这个点到至少 3 个点的距离相同。

    • 假设答案点只到 2 个点距离相同,那么这个点在这两个点的垂直平分线上,并且可以向外移动只到与另外的 1 个点距离相同。

    基于上面的结论,我们可以枚举三角形,求出外心,如果外心在多边形内就可以直接计算答案。如果在外面,就取三条垂直平分线与多边形边的交点计算答案。

    判断是否在内部可以用向量叉乘。

    时间复杂度 \(\mathcal O(n^4)\)

    Code

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #define N 105
    #define inf 2147483647.0
    #define eps 1e-60
    #define db long double
    using namespace std;
    struct Point
    {
        db x,y;
    }p[N];
    int n,a,b;
    db ans;
    db sqr(db x) {return x*x;}
    bool check(db k1,db b1,db k2,db b2,db k3,db b3,db x,db y)
    {
        int bjsum=0,bj[N];
        db xl[N][3],cc[N];
        for (int i=1;i<=n;++i)
            xl[i][1]=x-p[i].x,xl[i][2]=y-p[i].y;
        xl[n+1][1]=xl[1][1];
        xl[n+1][2]=xl[1][2];
        for (int i=1;i<=n;++i)
            cc[i]=xl[i][1]*xl[i+1][2]-xl[i][2]*xl[i+1][1];
        for (int i=1;i<=n;++i)
            if (cc[i]>0)
            {
                bj[i]=1;
                bjsum++;
            }
            else bj[i]=0;
        if (bjsum==0||bjsum==n) return true;
        for (int i=1;i<=n;++i)
        {
            if (bjsum==1&&bj[i]==1)
            {
                a=i,b=i+1;
                return false;
            }
            if (bjsum!=n&&bj[i]==0)
            {
                a=i;b=i+1;
                return false;
            }
        }
        if (!a&&!b)
        {
            for (int i=1;i<=n;++i)
            {
                if (bjsum!=0&&bj[i]==1) 
                {
                    a=i;b=i+1;
                    if (b>n) b=1;
                    db kk=0,bb=0,xx=0,yy=0;
                    if (abs(p[a].x-p[b].x)<eps) kk=inf;
                    else kk=(p[a].y-p[b].y)/(p[a].x-p[b].x);
                    if (kk!=inf) bb=p[a].y-kk*p[a].x;
                    if (abs(kk-inf)<eps) xx=p[a].x,yy=k1*xx+b1;
                    else xx=(b1-bb)/(kk-k1),yy=kk*xx+bb;
                    if (check(k1,b1,k2,b2,k3,b3,xx,yy)) return false;
                }
                if (bjsum!=n&&bj[i]==0)
                {
                    a=i;b=i+1;
                    if (b>n) b=1;
                    db kk=0,bb=0,xx=0,yy=0;
                    if (abs(p[a].x-p[b].x)<eps) kk=inf;
                    else kk=(p[a].y-p[b].y)/(p[a].x-p[b].x);
                    if (kk!=inf) bb=p[a].y-kk*p[a].x;
                    if (abs(kk-inf)<eps) xx=p[a].x,yy=k1*xx+b1;
                    else xx=(b1-bb)/(kk-k1),yy=kk*xx+bb;
                    if (check(k1,b1,k2,b2,k3,b3,xx,yy)) return false;
                }
            }
        }
        return false;
    }
    void calc(db xx,db yy)
    {
        db sum=inf;
        for (int i=1;i<=n;++i)
            sum=min(sum,sqrt(sqr(p[i].x-xx)+sqr(p[i].y-yy)));
        ans=max(ans,sum);
    }
    int main()
    {
        freopen("position.in","r",stdin);
        freopen("position.out","w",stdout);
        scanf("%d",&n);
        for (int i=1;i<=n;++i)
            scanf("%Lf%Lf",&p[i].x,&p[i].y);
        for (int i=1;i<=n;++i)
            for (int j=i+1;j<=n;++j)
                for (int k=j+1;k<=n;++k)
                {
                    db midx1,midx2,midy1,midy2,midx3,midy3,k1,k2,k3,b1,b2,b3,x1,x2,x3,y1,y2,y3;
                    db pointx,pointy;
                    x1=p[i].x;y1=p[i].y;
                    x2=p[j].x;y2=p[j].y;
                    x3=p[k].x;y3=p[k].y;
                    midx1=(x1+x2)/2;midy1=(y1+y2)/2;
                    midx2=(x2+x3)/2;midy2=(y2+y3)/2;
                    midx3=(x3+x1)/2;midy3=(y3+y1)/2;
                    if (y2==y1) k1=inf;
                    else k1=(x1-x2)/(y2-y1);
                    if (y3==y2) k2=inf;
                    else k2=(x2-x3)/(y3-y2);
                    if (y3==y1) k3=inf;
                    else k3=(x3-x1)/(y1-y3);
                    if (k1!=inf) b1=midy1-k1*midx1;
                    if (k2!=inf) b2=midy2-k2*midx2;
                    if (k3!=inf) b3=midy3-k3*midx3;
                    if (abs(k1-k2)<eps) continue;
                    if (k1==inf) pointx=midx1,pointy=k2*midx1+b2;
                    if (k2==inf) pointx=midx2,pointy=k1*midx2+b1;
                    if (k1!=inf&&k2!=inf)
                    {
                        pointx=(b2-b1)/(k1-k2);
                        pointy=(k1*b2-k2*b1)/(k1-k2);
                    }
                    a=b=0;
                    if (check(k1,b1,k2,b2,k3,b3,pointx,pointy))
                    {
                        calc(pointx,pointy);
                    }
                    else
                    {
                        db kk,bb,xx,yy;
                        if (b>n) b=1;
                        if (abs(p[a].x-p[b].x)<eps) kk=inf;
                        else kk=(p[a].y-p[b].y)/(p[a].x-p[b].x);
                        if (kk!=inf) bb=p[a].y-kk*p[a].x;
                        if (abs(kk-inf)<eps) xx=p[a].x,yy=k1*xx+b1;
                        else xx=(b1-bb)/(kk-k1),yy=kk*xx+bb;
                        calc(xx,yy);
                        if (abs(kk-inf)<eps) xx=p[a].x,yy=k2*xx+b2;
                        else xx=(b2-bb)/(kk-k2),yy=kk*xx+bb;
                        calc(xx,yy);
                        if (abs(kk-inf)<eps) xx=p[a].x,yy=k3*xx+b3;
                        else xx=(b3-bb)/(kk-k3),yy=kk*xx+bb;
                        calc(xx,yy);
                    }
                }
        printf("%.3Lf\n",ans);
        return 0;
    }
    
  • 相关阅读:
    利用Python 统计txt 文档词频 次数
    Markdown工具Typora结合gitee码云图床自动上传云端图片
    主数据MDM下发eHR系统操作整理v1.0
    Python读取Excel数据生成图表 v2.0
    HTML基础(20200610)
    Python网络编程socket 简易聊天窗
    selenium-python-验证码-动态验证码
    selenium-python-验证码-滑动验证码
    Linux系统学习 20200506
    @Mapper @Insert 注解式方法批量入库(ORACLE数据库)
  • 原文地址:https://www.cnblogs.com/Livingston/p/15824071.html
Copyright © 2011-2022 走看看