HDU - 5531- E - Rebuild(几何)

版权声明:沃斯里德小浩浩啊 https://blog.csdn.net/Healer66/article/details/83511091

链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5531

题意:

顺序给出二维坐标系中的点,让你找出以每个点为圆心的圆,使得相邻的点对应的圆相切,问圆的最小面积之和是多少.

思路:

这题其实比赛时就看出来了点端倪,看了题解加深了认识.

这题有以下特点:

1.确定第一个点的半径,则其余的半径都能确定.

2.第一个点半径改变,偶数点的变化与其相反,奇数点与之相同.

3.半径必须大于等于0(这个是用来判断半径是否合理的).

4.奇数个点时,如果存在答案,则答案唯一.

   

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
const double eps = 1e-10;
const int maxn = 1e5 +10;
double len[maxn],f[maxn],x;
int n;
struct Point
{
    double x,y;
} point[maxn];
double length(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void init()
{
    for(int i = 0 ; i < n-1; i++)
    {
        len[i] = length(point[i],point[i+1]);
    }
    len[n-1] = length(point[0],point[n-1]);
}
void print(double ans)
{
    printf("%.2f\n",ans * pi);
    for(int i = 0; i < n ; i++)
    {
        if(i & 1)
            printf("%.2f\n",f[i]-x);
        else
            printf("%.2f\n",f[i]+x);
    }
    return ;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        double maxx = 0x3f3f3f3f, minn =0;
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
            scanf("%lf%lf",&point[i].x,&point[i].y);
        init();
        f[0] = 0;
        //先假设半径 r - 0 求出相应的半径
        //注意,此时求出的半径,都是极限半径,偶数点对应极限大,奇数点对应极限小
        //据此判断出半径的范围
        for(int i = 1; i < n; i++)
        {
            f[i] = len[i-1] - f[i-1];
            if((i&1) && f[i] < maxx)
            {
                maxx = f[i];
            }
            if(!(i & 1) &&(-f[i]) > minn)
            {
                minn = -f[i];
            }
        }
        if(minn >= maxn + eps )
        {
            printf("IMPOSSIBLE\n");
            continue;
        }
        if(n & 1)
        {
            x = 1.0*(len[n-1] - f[n-1]) / 2.0; //根据最后一个半径的长度确定的
            if(x <= minn - eps || x >= maxx + eps)
            {
                printf("IMPOSSIBLE\n");
                continue;
            }
            double ans = 0.0;
            for(int i = 0; i < n ; i++)
            {
                if(i & 1)
                {
                    ans += (f[i] - x) * (f[i] - x);
                }
                else
                {
                    ans += (f[i] + x) * (f[i] + x);
                }
            }
            print(ans);
        }
        else
        {
            if( fabs(f[n-1]-len[n-1]) > eps || (minn - maxx) > eps)
            {
                printf("IMPOSSIBLE\n");
                continue;
            }
            double a = 0,b = 0, c = 0;
            for(int i = 0; i < n; i++)//偶数情况,构成二次函数,判断对称轴和半径取值范围即可
            {
                a = a + 1;
                c += f[i] * f[i];
                if(i & 1)
                {
                    b -= 2 * f[i];
                }
                else
                {
                    b += 2 * f[i];
                }
            }
            double l = (-b / 2) / a;
            if( l < minn + eps)
            {
                x = minn;
            }
            else if( maxx < l + eps)
            {
                x = maxx;
            }
            else x = l;
            print(a * x * x + b * x + c);
        }
    }
    return 0;
}

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

猜你喜欢

转载自blog.csdn.net/Healer66/article/details/83511091
今日推荐