HDU 5531 几何公式

来源:互联网 发布:华讯网络好吗 编辑:程序博客网 时间:2024/05/29 15:08
#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

0 0
原创粉丝点击