zoukankan      html  css  js  c++  java
  • POJ 3384 Feng Shui

    POJ_3384

        题目的意思是说在多边形内安排两个圆,使得两个圆覆盖的区域尽可能大(重合的部分只算一次),求两个圆的圆心坐标。

        首先,受POJ_3525这个题目的启发,我们先将凸多边形的边都向内收缩R,这样得到了一个新的凸多边形(新凸多边形的各个顶点可以通过求半平面交得到),那么两个圆的圆心必定在这个新凸多边形中,否则就会和原来的凸多边形的某条边相交。

        现在圆心的可行域找到了,那么在什么情况下两个圆覆盖的区域最大呢?我们可以直观的看到两个圆离的越近,重合的部分就越大,那么也就是说两个圆离得越远越好,而怎么衡量远近呢?圆心距!于是我们就得到了进一步的算法,枚举新凸多边形的任意两个顶点,找到距离最远的两个顶点,这两个顶点就可以作为两个圆的圆心了。之所以可以这么做,是因为凸多边形上相距最远的两个点必然都是凸多边形的顶点。

        此外在找凸多边形上相距最远的两个顶点是有更快的算法的,如果我没记错的话应该是“旋转卡壳”,但由于这个题目数据范围不大,而且前面我用于求半平面交的算法是O(n^2)的(求半平面交有O(nlogn)的算法,详见朱泽园的相关论文),所以后面用O(n^2)的算法去求凸多边形上相距最远的两个顶点也是可以接受的。

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define MAXD 210
    #define zero 1e-8
    #define INF 2000
    struct point
    {
    double x, y;
    }p[MAXD], wa[MAXD], wb[MAXD], *a, *b;
    int N, R, na, nb;
    double det(double x1, double y1, double x2, double y2)
    {
    return x1 * y2 - x2 * y1;
    }
    int dcmp(double x)
    {
    return fabs(x) < zero ? 0 : (x < 0 ? -1 : 1);
    }
    double sqr(double x)
    {
    return x * x;
    }
    void init()
    {
    int i, j, k;
    for(i = 0; i < N; i ++)
    scanf("%lf%lf", &p[i].x, &p[i].y);
    p[N] = p[0];
    }
    void add(double x, double y)
    {
    b[nb].x = x, b[nb].y = y;
    ++ nb;
    }
    void cut(int k)
    {
    int i, j;
    double x, y, t1, t2, dx, dy;
    t1 = sqrt(sqr(p[k + 1].x - p[k].x) + sqr(p[k + 1].y - p[k].y));
    dx = (p[k].y - p[k + 1].y) / t1 * R;
    dy = (p[k + 1].x - p[k].x) / t1 * R;
    point *t;
    nb = 0;
    for(i = 0; i < na; i ++)
    {
    t1 = det(p[k + 1].x - p[k].x, p[k + 1].y - p[k].y, a[i].x + dx - p[k].x, a[i].y + dy - p[k].y);
    t2 = det(p[k + 1].x - p[k].x, p[k + 1].y - p[k].y, a[i + 1].x + dx - p[k].x, a[i + 1].y + dy - p[k].y);
    if(dcmp(t1) <= 0)
    add(a[i].x, a[i].y);
    if(dcmp(t1) * dcmp(t2) < 0)
    {
    x = (fabs(t2) * a[i].x + fabs(t1) * a[i + 1].x) / (fabs(t1) + fabs(t2));
    y = (fabs(t2) * a[i].y + fabs(t1) * a[i + 1].y) / (fabs(t1) + fabs(t2));
    add(x, y);
    }
    }
    t = a, a = b, b = t;
    na = nb;
    a[na] = a[0];
    }
    void solve()
    {
    int i, j, k;
    double t, max, x1, y1, x2, y2;
    a = wa, b = wb;
    na = 4;
    a[0].x = -INF, a[0].y = -INF, a[1].x = -INF, a[1].y = INF, a[2].x = INF, a[2].y = INF, a[3].x = INF, a[3].y = -INF;
    a[na] = a[0];
    for(i = 0; i < N; i ++)
    cut(i);
    max = -1.0;
    for(i = 0; i < na; i ++)
    for(j = i; j < na; j ++)
    {
    t = sqrt(sqr(a[i].x - a[j].x) + sqr(a[i].y - a[j].y));
    if(dcmp(t - max) > 0)
    {
    x1 = a[i].x, y1 = a[i].y;
    x2 = a[j].x, y2 = a[j].y;
    max = t;
    }
    }
    printf("%.5lf %.5lf %.5lf %.5lf\n", x1, y1, x2, y2);
    }
    int main()
    {
    while(scanf("%d%d", &N, &R) == 2)
    {
    init();
    solve();
    }
    return 0;
    }


  • 相关阅读:
    Best Time to Buy and Sell Stock III
    Valid Palindrome
    Longest Substring Without Repeating Characters
    Copy List with Random Pointer
    Add Two Numbers
    Recover Binary Search Tree
    Anagrams
    ZigZag Conversion
    Merge k Sorted Lists
    Distinct Subsequences
  • 原文地址:https://www.cnblogs.com/staginner/p/2358587.html
Copyright © 2011-2022 走看看