#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 5;
const double INF = 1e20;
const double PI = acos(-1);
const double eps = 1e-8;
struct Point
{
double x, y;
Point(double x = 0, double y = 0): x(x), y(y) {}
};
int dcmp(double x)//
{
if (fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
double Distance(Point A, Point B)
{
return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
double Distance2(Point A, Point B)
{
return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
}
Point read_point()
{
double X, Y;
scanf("%lf%lf", &X, &Y);
return Point(X, Y);
}
Point P[maxn];
int n, T;
double L, R, A[maxn], Dis[maxn];
double get(double m)
{
double ret = m * m;
A[0] = m;
for (int i = 1; i < n; i++)
{
m = Dis[i - 1] - m;
ret += m * m;
A[i] = m;
}
return ret;
}
double solve ()
{
while (R - L > eps)
{
double l = (2 * L + R) / 3;
double r = (L + 2 * R) / 3;
if (get(l) >= get(r)) L = l;
else R = r;
}
return L;
}
int main(int argc, char const *argv[])
{
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
P[i] = read_point();
P[n] = P[0];
double s = 0, ans = 0;
L = 0, R = INF;
for (int i = 0; i < n; i++)
{
Dis[i] = Distance(P[i], P[i + 1]);
s = Dis[i] - s; ans = Dis[i] - ans;
if (i & 1) L = max(L, -s);
else R = min(R, s);
}
if ((L > R) || (n % 2 == 0 && dcmp(ans) != 0)) printf("IMPOSSIBLE\n");
else
{
if (n & 1) ans /= 2;
else ans = solve();
printf("%.2lf\n", get(ans) * PI);
for (int i = 0; i < n; i++) printf("%.2lf\n", A[i]);
}
}
return 0;
}
没有想出做法,看了题解。
题意:按顺序给出一个多边形,以多边形的每个顶点为圆心作圆,使得任意两相邻点对应的圆相切,求所有圆面积总和的最小值。
画个图算两下就出来了,发现只需要对n的奇偶性进行讨论即可。
设每个点为pi(0 <= i <= n - 1),对应圆的半径为ri,pi和p(i + 1)(默认pn为p0)的距离为di,则很显然我们得到了n个方程:
Fi:ri + r(i + 1) = di(0 <= i <= n - 1)。
通过这个方程我们发现,全部加起来除以2即得到了所有ri的和。当n为奇数时,将i为奇数的方程Fi相加可以得到r1 + r2 + ...... + r(n - 1)的和,再用总和减去它即得到了r0,也就是说,n为奇数时,这个方程组有唯一解,所以,解出所有的解,只要所有解都非负即可算出答案,如果有负的就IMPOSSIBLE。当n为偶数时,i为偶数的方程相加和i为奇数的方程相加的结果应该是一样的(都等于所有ri之和)。所以先算这两个和,如果这两个和不相等,也是IMPOSSIBLE。其次,我们从第二个方程起,可以将每个ri都变成与r0相关的式子,这样,所有圆的面积都可以用r0表示,最后的总面积是关于r0的二次函数,直接求解最小值即可。设ri = ai*r0 + bi,
则r(i + 1) = di - ri = -ai*r0 - bi + di。所以a(i + 1) = -ai,b(i + 1) = - bi + di。a0 = 1,b0 = 0。这样求出每个ai和bi(可以发现ai只有1和-1),然后面积和 = pi*sigma(ri^2,0 <= i <= n - 1) = A*r0^2 + B*r0 + C,算出A,B,C的值再根据每个ri的范围(0 <= ri <= min(di,d(i + 1))求出r0的取值范围(即维护区间的左右端点),如果区间右端点小于左端点,则无解IMPOSSIBLE。否则根据二次函数性质算出区间内最低点即可。
题解来自:http://blog.csdn.net/firstlucker/article/details/49557517