HDU 5531 几何公式

#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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值