POJ 3384 Feng Shui (半平面交求多边形内两个圆最大面积)

来源:互联网 发布:网络电子老虎机技巧 编辑:程序博客网 时间:2024/05/16 06:40


Feng Shui
Time Limit: 2000MS
Memory Limit: 65536KTotal Submissions: 3743
Accepted: 1150
Special Judge

Description

Feng shui is the ancient Chinese practice of placement and arrangement of space to achieve harmony with the environment. George has recently got interested in it, and now wants to apply it to his home and bring harmony to it.

There is a practice which says that bare floor is bad for living area since spiritual energy drains through it, so George purchased two similar round-shaped carpets (feng shui says that straight lines and sharp corners must be avoided). Unfortunately, he is unable to cover the floor entirely since the room has shape of a convex polygon. But he still wants to minimize the uncovered area by selecting the best placing for his carpets, and asks you to help.

You need to place two carpets in the room so that the total area covered by both carpets is maximal possible. The carpets may overlap, but they may not be cut or folded (including cutting or folding along the floor border) — feng shui tells to avoid straight lines.

Input

The first line of the input file contains two integer numbers n and r — the number of corners in George’s room (3 ≤ n ≤ 100) and the radius of the carpets (1 ≤ r ≤ 1000, both carpets have the same radius). The following n lines contain two integers xi and yi each — coordinates of the i-th corner (−1000 ≤ xiyi ≤ 1000). Coordinates of all corners are different, and adjacent walls of the room are not collinear. The corners are listed in clockwise order.

Output

Write four numbers x1y1x2y2 to the output file, where (x1y1) and (x2y2) denote the spots where carpet centers should be placed. Coordinates must be precise up to 4 digits after the decimal point.

If there are multiple optimal placements available, return any of them. The input data guarantees that at least one solution exists.

Sample Input

#15 2
-2 0
-5 3
0 8
7 3
5 0
#24 3
0 0
0 8
10 8
10 0

Sample Output

#1-2 3 3 2.5#23 5 7 3

Hint

Source

Northeastern Europe 2006, Northern Subregion

POJ_3384

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

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

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

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


/* ***********************************************Author        :kuangbinCreated Time  :2013/8/18 15:52:28File Name     :F:\2013ACM练习\专题学习\计算几何\半平面交\POJ3384.cpp************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;const double eps = 1e-8;const double PI = acos(-1.0);int sgn(double x){    if(fabs(x) < eps) return 0;    if(x < 0) return -1;    else return 1;}struct Point{    double x,y;    Point(){}    Point(double _x,double _y)    {        x = _x; y = _y;    }    Point operator -(const Point &b)const    {        return Point(x - b.x, y - b.y);    }    double operator ^(const Point &b)const    {        return x*b.y - y*b.x;    }    double operator *(const Point &b)const    {        return x*b.x + y*b.y;    }};struct Line{    Point s,e;    double k;    Line(){}    Line(Point _s,Point _e)    {        s = _s; e = _e;        k = atan2(e.y - s.y,e.x - s.x);    }    Point operator &(const Line &b)const    {        Point res = s;        double t = ((s - b.s)^(b.s - b.e))/((s - e)^(b.s - b.e));        res.x += (e.x - s.x)*t;        res.y += (e.y - s.y)*t;        return res;    }};//半平面交,直线的左边代表有效区域bool HPIcmp(Line a,Line b){    if(fabs(a.k - b.k) > eps)return a.k < b.k;    return ((a.s - b.s)^(b.e - b.s)) < 0;}Line Q[1010];void HPI(Line line[], int n, Point res[], int &resn){    int tot = n;    sort(line,line+n,HPIcmp);    tot = 1;    for(int i = 1;i < n;i++)        if(fabs(line[i].k - line[i-1].k) > eps)            line[tot++] = line[i];    int head = 0, tail = 1;    Q[0] = line[0];    Q[1] = line[1];    resn = 0;    for(int i = 2; i < tot; i++)    {        if(fabs((Q[tail].e-Q[tail].s)^(Q[tail-1].e-Q[tail-1].s)) < eps || fabs((Q[head].e-Q[head].s)^(Q[head+1].e-Q[head+1].s)) < eps)            return;        while(head < tail && (((Q[tail]&Q[tail-1]) - line[i].s)^(line[i].e-line[i].s)) > eps)            tail--;        while(head < tail && (((Q[head]&Q[head+1]) - line[i].s)^(line[i].e-line[i].s)) > eps)            head++;        Q[++tail] = line[i];    }    while(head < tail && (((Q[tail]&Q[tail-1]) - Q[head].s)^(Q[head].e-Q[head].s)) > eps)        tail--;    while(head < tail && (((Q[head]&Q[head-1]) - Q[tail].s)^(Q[tail].e-Q[tail].e)) > eps)        head++;    if(tail <= head + 1)return;    for(int i = head; i < tail; i++)        res[resn++] = Q[i]&Q[i+1];    if(head < tail - 1)        res[resn++] = Q[head]&Q[tail];}Point p[1010];Line line[1010];//*两点间距离double dist(Point a,Point b){    return sqrt((a-b)*(a-b));}void change(Point a,Point b,Point &c,Point &d,double p)//将线段ab往左移动距离p{    double len = dist(a,b);    double dx = (a.y - b.y)*p/len;    double dy = (b.x - a.x)*p/len;    c.x = a.x + dx; c.y = a.y + dy;    d.x = b.x + dx; d.y = b.y + dy;}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int n;    double r;    while(scanf("%d%lf",&n,&r) == 2)    {        for(int i = 0;i < n;i++)            scanf("%lf%lf",&p[i].x,&p[i].y);        reverse(p,p+n);        for(int i = 0;i < n;i++)        {            Point t1,t2;            change(p[i],p[(i+1)%n],t1,t2,r);            line[i] = Line(t1,t2);        }        int resn;        HPI(line,n,p,resn);        int res1 = 0, res2 = 0;        for(int i = 0;i < resn;i++)            for(int j = i;j < resn;j++)                if(dist(p[i],p[j]) > dist(p[res1],p[res2]))                    res1 = i, res2 = j;        printf("%.5f %.5f %.5f %.5f\n",p[res1].x,p[res1].y,p[res2].x,p[res2].y);    }    return 0;}



0 0
原创粉丝点击