zoukankan      html  css  js  c++  java
  • poj 3525 半平面交求多边形内切圆最大半径【半平面交】+【二分】

    <题目链接>

    题目大意:
    给出一个四面环海的凸多边形岛屿,求出这个岛屿中的点到海的最远距离。

    解题分析:

    仔细思考就会发现,其实题目其实就是让我们求该凸多边形内内切圆的最大半径是多少。但是,这个最大半径,没有什么比较好的求法,于是,我们可以想到二分答案求半径。对于二分的半径,我们可以将该凸多边形的边界向内平移 r 的距离,然后再用半平面交法,用这些平移后的直线去切割原凸多边形,如果最终切得的区域不为空,则二分枚举更大的半径,反之减小枚举的半径。知道恰好围成的区域为空(或恰好不为空)为止。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    
    const double eps = 1e-8;
    const double inf = 1e9;
    const int MAXN = 210;
    int m;//保存多边形的点数
    double r;//保存内移距离
    int cCnt, curCnt;//此时cCnt为最终切割得到的多边形的顶点数、暂存顶点个数
    
    struct point
    {
        double x, y;
    };
    point points[MAXN], p[MAXN], q[MAXN];//读入的多边形的顶点(顺时针)、p为存放最终切割得到的多边形顶点的数组、暂存核的顶点
    
    void getline(point x, point y, double &a, double &b, double   &c) //两点x、y确定一条直线a、b、c为其系数
    {
        a = y.y - x.y;
        b = x.x - y.x;
        c = y.x * x.y - x.x * y.y;
    }
    
    void initial()
    {
        for (int i = 1; i <= m; ++i)p[i] = points[i];
        p[m + 1] = p[1];
        p[0] = p[m];
        cCnt = m;
    }
    
    point intersect(point x, point y, double a, double b, double c)        //定比分点法,求两条直线的交点
    {
        double u = fabs(a * x.x + b * x.y + c);
        double v = fabs(a * y.x + b * y.y + c);
        point pt;
        pt.x = (x.x * v + y.x * u) / (u + v);
        pt.y = (x.y * v + y.y * u) / (u + v);
        return  pt;
    }
    
    void cut(double a, double b, double c)               //利用半平面交求出切割后多边形的所有顶点
    {
        curCnt = 0;
        for (int i = 1; i <= cCnt; ++i)             
        {
            if (a*p[i].x + b * p[i].y + c >= 0)q[++curCnt] = p[i];     // c因为精度问题,可能会偏小。所以有些点本应在右側而没在。
            else
            {
                if (a*p[i - 1].x + b * p[i - 1].y + c > 0)
                {
                    q[++curCnt] = intersect(p[i], p[i - 1], a, b, c);
                }
                if (a*p[i + 1].x + b * p[i + 1].y + c > 0)
                {
                    q[++curCnt] = intersect(p[i], p[i + 1], a, b, c);
                }
            }
        }
    
        for (int i = 1; i <= curCnt; ++i)p[i] = q[i];
        p[curCnt + 1] = q[1];
        p[0] = p[curCnt];
        cCnt = curCnt;
    }
    
    int dcmp(double x)    //控制精度
    {
        if (fabs(x)<eps) return 0;
        else return x<0 ? -1 : 1;
    }
    
    void solve()
    {
        initial();        //初始化存放多边形顶点的p数组
    
        for (int i = 1; i <= m; ++i) {
    
            point ta, tb, tt;                   //得到平移后的直线
            tt.x = points[i + 1].y - points[i].y;
            tt.y = points[i].x - points[i + 1].x;
            double k = r / sqrt(tt.x * tt.x + tt.y * tt.y);
            tt.x = tt.x * k;
            tt.y = tt.y * k;
            ta.x = points[i].x + tt.x;
            ta.y = points[i].y + tt.y;
            tb.x = points[i + 1].x + tt.x;
            tb.y = points[i + 1].y + tt.y;
    
    
            double a, b, c;           //接下来用这些平移后的直线去切割原多边形
            getline(ta, tb, a, b, c);
            cut(a, b, c);
        }
    }
    
    void Reverse() { //规整化方向,逆时针变顺时针,顺时针变逆时针
        for (int i = 1; i < (m + 1) / 2; i++)
            swap(points[i], points[m - i]);          
    }
    
    int main()
    {
        while (scanf("%d", &m) != EOF) {
            if (m == 0) break;
            for (int i = 1; i <= m; i++)
                scanf("%lf%lf", &points[i].x, &points[i].y);
            Reverse();          //由于点的顺序是逆时针输入,所以要将它改成顺时针
            points[m + 1] = points[1];
            
            double left = 0, right = inf, mid;
            while ((right - left) >= eps) {        //二分求半径,eps控制二分的精度
                mid = (left + right) / 2.0;
                r = mid;                           //r为内切圆半径
                solve();
                if (cCnt <= 0) right = mid;     //如果将该多边形顶点向内平移r的距离后,半平面交所得多边形为空,则说明r过大,应当适当缩小
                else left = mid;
            }
            printf("%.6f
    ", left);
        }
        return 0;
    }

    2018-08-03

  • 相关阅读:
    CSS简要内容
    HTML简要内容
    java中的多线程
    java中的IO流
    hash
    java中的集合
    java中的数组
    java中的异常机制(编译时异常)
    静态变量和静态方法的访问权限
    成员变量和成员方法的访问权限
  • 原文地址:https://www.cnblogs.com/00isok/p/9416895.html
Copyright © 2011-2022 走看看