HDU - 5531- E - Rebuild(幾何)
連結:
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; }