hdu5531Rebuild+三分

来源:互联网 发布:辽宁北方网络 编辑:程序博客网 时间:2024/05/14 09:39

Problem Description
Archaeologists find ruins of Ancient ACM Civilization, and they want to rebuild it.

The ruins form a closed path on an x-y plane, which has n endpoints. The endpoints locate on (x1,y1), (x2,y2), …,(xn,yn) respectively. Endpoint i and endpoint i−1 are adjacent for 1< i≤n, also endpoint 1 and endpoint n are adjacent. Distances between any two adjacent endpoints are positive integers.

To rebuild, they need to build one cylindrical pillar at each endpoint, the radius of the pillar of endpoint i is ri. All the pillars perpendicular to the x-y plane, and the corresponding endpoint is on the centerline of it. We call two pillars are adjacent if and only if two corresponding endpoints are adjacent. For any two adjacent pillars, one must be tangent externally to another, otherwise it will violate the aesthetics of Ancient ACM Civilization. If two pillars are not adjacent, then there are no constraints, even if they overlap each other.

Note that ri must not be less than 0 since we cannot build a pillar with negative radius and pillars with zero radius are acceptable since those kind of pillars still exist in their neighbors.

You are given the coordinates of n endpoints. Your task is to find r1,r2,…,rn which makes sum of base area of all pillars as minimum as possible.

这里写图片描述

For example, if the endpoints are at (0,0), (11,0), (27,12), (5,12), we can choose (r1, r2, r3, r4)=(3.75, 7.25, 12.75, 9.25). The sum of base area equals to 3.752π+7.252π+12.752π+9.252π=988.816…. Note that we count the area of the overlapping parts multiple times.

If there are several possible to produce the minimum sum of base area, you may output any of them.

Input
The first line contains an integer t indicating the total number of test cases. The following lines describe a test case.

The first line of each case contains one positive integer n, the size of the closed path. Next n lines, each line consists of two integers (xi,yi) indicate the coordinate of the i-th endpoint.

1≤t≤100
3≤n≤104
|xi|,|yi|≤104
Distances between any two adjacent endpoints are positive integers.

Output
If such answer doesn’t exist, then print on a single line “IMPOSSIBLE” (without the quotes). Otherwise, in the first line print the minimum sum of base area, and then print n lines, the i-th of them should contain a number ri, rounded to 2 digits after the decimal point.

If there are several possible ways to produce the minimum sum of base area, you may output any of them.

Sample Input

3
4
0 0
11 0
27 12
5 12
5
0 0
7 0
7 3
3 6
0 6
5
0 0
1 0
6 12
3 16
0 12

Sample Output

988.82
3.75
7.25
12.75
9.25
157.08
6.00
1.00
2.00
3.00
0.00
IMPOSSIBLE

Source
2015ACM/ICPC亚洲区长春站-重现赛(感谢东北师大)

给出n个点,这n个点可以连成一个凸多边形。现在以多边形的端点作为圆心,分别做n个圆,要求在同一条线上的端点的圆是相切的。现在要求满足条件以后,计算最小的圆面积总和。如果不能保证条件成立,则输出impossible。

解法:我们假设第一个圆的半径为R,那么第二个就可以确定是dis[1]-R,由此类推,后边的圆的半径都可以确定了。
首先我们要知道凸多边形的边长为什么意义?是所有圆的半径的2倍。此时可以发现。多边形为偶数边和奇数边不一样,(1)当多边形为偶数时,有奇数边的边长和为就是所有圆的半径和。(2)当多边形为奇数时,奇数边的边长和为就是所有圆的半径和+第一个圆的半径。
所以当(1)当多边形为奇数时,第一个圆的半径是唯一确定的,直接判断是否满足条件即可。(2),设第一个圆的半径为R是,总面积就是一个关于R的二次方程,所以用三分求最值。
至于:最后要注意的地方就是三分半径的上下界,我们可以假设第一个圆的半径是0,那么第二个圆应该是一个最大的半径的。(找个最小的出来),第三个又是最小的,(找个最大的出来,取负),我们注意到。如果某个圆是负数,且他的绝对值要比上界还大,这是个“IMPOSSIBLE”的情况,

#include<bits/stdc++.h>using namespace std;#define pi acos(-1.0)struct point {    double x,y;};point a[10005];double R[10004]; //圆的半径double dis[10004];//边长int n;double alldis; //四边形边长和double oudis,jidis; //偶数边边长和,奇数边边长和double LL,RR;//半径的上下界double distances(point a,point b) {    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double getarea(double a0){ //第一个圆半径的总面积    double ans=a0*a0;    R[0]=a0;    for(int i=1;i<n;i++){        R[i]=dis[i-1]-R[i-1];        ans+=R[i]*R[i];    }    return ans;}void getdis() {    alldis=0;    oudis=jidis=0;    for(int i=0; i<n; i++) {        dis[i]=distances(a[i],a[(i+1)%n]);        alldis+=dis[i];        if(i%2==0) oudis+=dis[i];        else jidis+=dis[i];    }    alldis/=2;/*************************/    LL=0,RR=1e9;    getarea(0);    for (int i = 0; i < n; i++){        if (i&1) RR = min(RR, R[i]);        else LL = max(LL,-R[i]);    }}double judgeR(){ //判断半径是否都合法    for(int i=0;i<n;i++){        if(R[i]<0) return false;    }    return true;}int main() {    int t;    scanf("%d",&t);    while(t--) {        scanf("%d",&n);        for(int i=0; i<n; i++) scanf("%lf %lf",&a[i].x,&a[i].y);        getdis();        if(n%2==1) { //奇数情况            double ans=getarea(oudis-alldis);            if(judgeR()==true) {                printf("%.2f\n",ans*pi);                for(int j=0; j<n; j++) printf("%.2f\n",R[j]);            } else {                printf("IMPOSSIBLE\n");            }        } else {//偶数情况            if(fabs(oudis-jidis)>0.000001||LL>RR) {                printf("IMPOSSIBLE\n");            } else {                while(RR-LL>0.000001) { //三分半径                    double m1=(2*LL+RR)/3,m2=(LL+2*RR)/3;                    if(getarea(m1)>=getarea(m2)) LL=m1;                    else RR=m2;                }                double  ans=getarea((LL+RR)/2);                printf("%.2f\n",ans*pi);                for(int j=0; j<n; j++) printf("%.2f\n",R[j]);            }        }    }    return 0;}
1 0
原创粉丝点击