Rebuild-HDU - 5531 (计算几何)
题目链接: HDU - 5531
题意:
给定一个含有(mathit n) 个节点的闭合图形((i-i+1) 连边,( ext 1) 和(mathit n) 连边),要求你以每一个节点为圆心做一个半径值大于零的圆,且相邻节点的圆相切。问所有圆的面积最小值是多少?
思路:
设(x_i)为第(mathit i) 个节点的半径值,根据题意我们可以列出
我们将(x_2,x_3,dots,x_n)用 (x_1)代替可得:
容易发现 当 (mathit n) 是奇数的时候,
存在 , 所以和 前面对应的方程联立,
可以直接解出来所有(x_i)。
当(mathit n) 是偶数的时候,存在很多可能的解,且容易知道面积和一定一个关于(x_1)的一元二次函数,那么我们确定一下(x_1)的上下界之后,三分找最小值即可。
上下界主要通过考虑画圆时满足每个圆的半径大于零且相切的极限情况。
思路:
#include <bits/stdc++.h>
using namespace std;
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define eps 1e-8
typedef long long ll;
typedef double db;
struct Point {
db x, y;
Point() {}
Point(db xx, db yy) {x = xx, y = yy;}
Point operator - (const Point &b) const
{
return Point(x - b.x, y - b.y);
}
db operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
db operator * (const Point &b)const
{
return x * b.x + y * b.y;
}
db distance(Point p)
{
return (hypot(x - p.x, y - p.y));
}
void input()
{
int xx, yy;
scanf("%d %d", &xx, &yy);
x = xx;
y = yy;
}
} arr[10010];
int n, t;
ll l[10010];
ll r[10010];
ll dist[10010];// d[i]= dis(a[i],a[i+1])
double R[10010];
const double pi = acos(-1);
double gao()
{
double res = R[1] * R[1];
for (int i = 2; i <= n; ++i) {
R[i] = dist[i - 1] - R[i - 1];
res += R[i] * R[i];
}
return res;
}
int main()
{
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
arr[i].input();
}
arr[n + 1] = arr[1];
for (int i = 1; i <= n; ++i) {
dist[i] = arr[i].distance(arr[i + 1]);
}
if (n & 1) {
double sum = 0;
for (int i = 1; i <= n; ++i) {
if (i & 1) {
sum += dist[i];
} else {
sum -= dist[i];
}
}
R[1] = 0.5 * sum;
double ans = 0;
int isok = 1;
repd(i, 1, n) {
R[i + 1] = dist[i] - R[i];
if (R[i] < 0 || R[i] > dist[i]) {
isok = 0;
}
ans += R[i] * R[i];
}
if (!isok) {
printf("IMPOSSIBLE
");
} else {
printf("%.2f
", (double)ans * pi);
for (int i = 1; i <= n; ++i) {
printf("%.2f
", (double)R[i]);
}
}
} else {
double sum = 0;
double low = 0;
double high = 1e18;
for (int i = 1; i <= n; ++i) {
if (i & 1) {
sum += dist[i];
high = min(high, sum);
} else {
sum -= dist[i];
low = max(low, sum);
}
}
if (fabs(sum) > eps || low > high ) {
printf("IMPOSSIBLE
");
} else {
for (int i = 1; i <= 200; ++i) {
double mid = (low + low + high) / 3.000000;
double mmid = (low + high + high) / 3.000000;
R[1] = mid;
double mv = gao();
R[1] = mmid;
double mmv = gao();
if (mv > mmv) {
low = mid;
} else {
high = mmid;
}
}
R[1] = high;
double ans = gao();
printf("%.2f
", ans * pi);
for (int i = 1; i <= n; ++i) {
printf("%.2f
", R[i]);
}
}
}
}
return 0;
}