Rebuild
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2483 Accepted Submission(s): 548
The ruins form a closed path on an x-y plane, which has n endpoints. The endpoints locate on
To rebuild, they need to build one cylindrical pillar at each endpoint, the radius of the pillar of endpoint i is
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
For example, if the endpoints are at (0,0) , (11,0) , (27,12) , (5,12) , we can choose ( r1 , r2 , r3 , r4 ) = (
If there are several possible to produce the minimum sum of base area, you may output any of them.
The first line of each case contains one positive integer
3≤n≤104
|xi|,|yi|≤104
Distances between any two adjacent endpoints are positive integers.
If there are several possible ways to produce the minimum sum of base area, you may output any of them.
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
988.82
3.75
7.25
12.75
9.25
157.08
6.00
1.00
2.00
3.00
0.00
IMPOSSIBLE
题目大意:
有
n
个点,其中这
解题思路:
因为保证相邻圆是相切的,所以我们设第一个圆的半径为
r1+r2=d1
r2+r3=d2
...
rn+r1=dn
然后我们来解这个方程,解的过程中就会发现有一个小规律,跟
n
的奇偶有关系,即:当
如果是偶数的话,我们发现解不出这个方程,那么怎么做的,因为求的是面积,所以最终的结果一定是关于
r1
的二次方程,又因为,二次函数我们可以通过 三分 来求得区间中的极值,我认为这个题的关键就是如何确定
r1
的三分范围,还是来考虑上述的方程,我们将其变形为:
r1≥0
d1−r1≥0
d2−d1+r1≥0
...
然后我们就能求得一个区间
[l,r]
, 因为这个区间中的数都是符合的,所以才进行三分。
还有一个小 trick 就是,偶数的时候我们必须求得验证一个条件:奇数边的距离是等于偶数边的距离的。
代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int MAXN = 1e4+5;
const double PI = acos(-1.0);
const double eps = 1e-8;
struct Point{
double x, y;
}p[MAXN];
double Dis(Point a, Point b){
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
double dis[MAXN], r[MAXN];
int n;
double f(double x)
{
r[0] = x;
double ans = r[0]*r[0];
for(int i=1; i<n; i++){
r[i] = dis[i-1]-r[i-1];
ans += r[i]*r[i];
}
return ans;
}
double sanfen(double left, double right)
{
double midl, midr;
while (right-left > eps)
{
midl = (left + right) / 2;
midr = (midl + right) / 2;
if(f(midl) <= f(midr)) right = midr;
else left = midl;
}
return left;
}
int main()
{
int T; scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
for(int i=0; i<n; i++) dis[i] = Dis(p[i], p[(i+1)%n]);
r[0] = 0;
for(int i=0; i<n; i++){
if(i & 1) r[0] -= dis[i];
else r[0] += dis[i];
}
if(n & 1){
r[0] /= 2;
double ans = PI*r[0]*r[0];
int ok = 0;
if(r[0]>-eps && r[0]<=dis[0]){
for(int i=1; i<n; i++){
r[i] = dis[i-1]-r[i-1];
if(r[i]<-eps || r[i]>dis[i]){
ok = 1;
break;
}
ans += PI*r[i]*r[i];
}
}
else ok = 1;
if(ok) puts("IMPOSSIBLE");
else{
printf("%.2f\n",ans);
for(int i=0; i<n; i++) printf("%.2f\n",r[i]);
}
}
else{
double l = 0, rr = 1e9;
if(fabs(r[0]) > eps) { puts("IMPOSSIBLE"); continue; }
double tmp = 0;
for(int i=1; i<n; i++){
tmp = dis[i-1] - tmp;
if(i & 1) rr = min(rr, tmp);
else l = max(l, -tmp);
}
double ans = sanfen(l, rr);
if(l > rr) puts("IMPOSSIBLE");
else{
printf("%.2f\n",f(ans)*PI);
for(int i=0; i<n; i++) printf("%.2f\n", r[i]);
}
}
}
return 0;
}