HDU - 5531(Rebuild )分析+三分

版权声明:SDKD-Vici__ https://blog.csdn.net/Vici__/article/details/83546037

题意:

给定一个n,代表有n个点,给出n个坐标,以每个坐标为圆心画圆。

要求:①相邻的两个点画的圆必须相切(第i个和第i+1个,及第一个点和最后一个点)

           ②所有圆的面积之和最小。

注:半径可以为0。

分析:

  1. 如果n为奇数,通过列方程可以知道,r1=(d1+d3+...-d2-d4-...)/2,可以发现r1是确定的。(不懂可以用n=3举个栗子,把方程列出来就明白了)
    那么就可以直接求r1,然后 r[i]=dist[i-1]-r[i-1] 依次把所有的r求出来,检验一下①是否有r是负数,②r[1]+r[n]是否等于dist[n];
  2. 如果n是偶数,列完方程后会发现,不能像n为奇数一样把r1用d1、d2...表示出来,则说明r1是不确定的,那么所有的r也不确定。(可以举个n=4的梨子,和n=3比较比较)
    那么答案我们无法直接求出,但可能存在一个最大值,用三分法求即可。

代码:

#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define clr(str,x) memset(str,x,sizeof(str))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);
#define INF 0x3f3f3f3f
#define maxn 10100

typedef long long int ll;
using namespace std;
const double PI =acos(-1.0);
double r[maxn],dist[maxn];
int n;
struct node
{
    double x,y;
} nodes[maxn];
double getDist(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double f(double r1)
{
    r[1]=r1;
    double sum=PI*r1*r1;
    for(int i=2; i<=n; i++)
    {
        r[i]=dist[i-1]-r[i-1];
        sum+=PI*r[i]*r[i];
    }
    return sum;
}
double Sanfen(double& l,double& r)
{
    int K=200;
    while(K--)
    {
        double mid=(l+r)/2;
        double mmid=(mid+r)/2;
        if(f(mid)<f(mmid))
            r=mmid;
        else
            l=mid;
    }
    return  f(l)<f(r) ? l:r;
}
int main()
{
    //FRER()
    //FREW()
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(r,0,sizeof(r));
        memset(dist,0,sizeof(dist));
        bool isyes=true;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf",&nodes[i].x,&nodes[i].y);
            if(i==1)
                continue;
            dist[i-1]=getDist(nodes[i],nodes[i-1]);
        }
        dist[n]=getDist(nodes[n],nodes[1]);
        if(n&1)
        {
            double s0=0;
            for(int i=1; i<=n; i++)
            {
                if(i&1)
                    s0+=dist[i];
                else
                    s0-=dist[i];
            }
            r[1]=s0/2;
            for(int i=2; i<=n; i++)
            {
                r[i]=dist[i-1]-r[i-1];
            }
            if(r[1]+r[n]!=dist[n])
                isyes=0;
        }
        else
        {
            double t1=0,t2=0;
            for(int i=1; i<=n; i++)
            {
                if(i&1)  t1+=dist[i];
                else  t2+=dist[i];
            }
            if(t1-t2!=0)
            {
                isyes=0;
            }
            else
            {
                double s0=0;
                double l=0,r=min(dist[1],dist[n]);
                for(int i=1; i<=n; i++)
                {
                    if(i&1)
                    {
                        s0+=dist[i];
                        r=min(r,s0);
                    }
                    else
                    {
                        s0-=dist[i];
                        l=max(l,s0);
                    }
                }
                double r1;
                r1=Sanfen(l,r);
                f(r1);
            }
        }
        for(int i=1;i<=n;i++)
            if(r[i]<0)
                isyes=false;
        if(!isyes)
            printf("IMPOSSIBLE\n");
        else
        {
            double ans=0;
            for(int i=1; i<=n; i++)
            {
                ans+=r[i]*r[i];
            }
            ans*=PI;
            printf("%.2lf\n",ans);
            for(int i=1; i<=n; i++)
                printf("%.2lf\n",r[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Vici__/article/details/83546037
今日推荐