题意:
给定一个n,代表有n个点,给出n个坐标,以每个坐标为圆心画圆。
要求:①相邻的两个点画的圆必须相切(第i个和第i+1个,及第一个点和最后一个点)
②所有圆的面积之和最小。
注:半径可以为0。
分析:
- 如果n为奇数,通过列方程可以知道,,可以发现r1是确定的。(不懂可以用n=3举个栗子,把方程列出来就明白了)
那么就可以直接求r1,然后 r[i]=dist[i-1]-r[i-1] 依次把所有的r求出来,检验一下①是否有r是负数,②r[1]+r[n]是否等于dist[n];- 如果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; }