HDU4752 Polygon

其实从算法上并不是太难,但是细节很多,时间很紧,精度很阴险,我就不多吐槽了= =


基本的结题思路就是先求出曲线和多边形的所有交点,将交点排序,然后求交点之间在多边形内部的长度和。


我一开始在排序后对每两个相邻交点计算他们的曲线中点在不在多边形内,结果O(n^2)肯定TLE= =

然后封哥指点说在多边形内的线段是交替出现的,然后我就去改啊,然后就TLE了= =(怎么还是TLE?)

然后赛后我把我原来自己写的朴素自适应积分法改成了simpson,精度调了个1e-8就过了哈哈哈!= =(其间是各种WAWAWATLETLETLE)


按交替的算的时候,要注意几个细节:

1. 二次函数只有一解时不能要,因为此时曲线始终在多边形某边一侧。

2. 还需要考虑曲线经过多边形顶点的情况,注意曲线要穿过多边形才能算该点。


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <algorithm>
using namespace std;

const int maxn = 20005;
const double eps = 1e-8;
int n, a, b, c, l, r;
int x[maxn], y[maxn];
double p[maxn*2];
int tot;

int dcmp(double x) {if (fabs(x) < eps) return 0; return x > 0 ? 1 : -1;}

double func(double x)
{
    return (a * x + b) * x + c;
}

bool between(double a, double b, double c) {return dcmp(a - b) > 0 && dcmp(c - a) > 0;}

bool solve(double a, double b, double c, double &x1, double &x2)
{
    double d = b*b - 4*a*c;
    if (dcmp(d) <= 0) return 0;
    d = sqrt(d);
    x1 = (-b - d) / a * 0.5;
    x2 = (-b + d) / a * 0.5;
    return 1;
}

void get(int x1, int y1, int x2, int y2)
{
    if (x1 == x2)
    {
        double y = func(x1);
        if (y1 > y2) swap(y1, y2);
        if (between(y, y1, y2)) p[tot++] = x1;
    }
    else
    {
        double k = (double)(y2 - y1) / (x2 - x1), r1, r2;
        if (solve(a, b - k, c + k * x1 - y1, r1, r2))
        {
            if (x1 > x2) swap(x1, x2);
            if (between(r1, x1, x2)) p[tot++] = r1;
            if (between(r2, x1, x2)) p[tot++] = r2;
        }
    }
}

double sqr(double x) {return x * x;}

double f(double x)
{
    return sqrt(sqr(2*a*x + b) + 1);
}

double simpson(double p1, double p2)
{
    double mid = (p1 + p2) / 2, mid1 = (p1 + mid) / 2, mid2 = (mid + p2) / 2;
    double f1 = f(p1), f2 = f(p2), fm = f(mid), fm1 = f(mid1), fm2 = f(mid2);
    double tmp = (f1 + fm * 4 + f2) * (p2 - p1) / 6;
    if (dcmp(tmp - (f1 + fm1 * 4 + fm) * (mid - p1) / 6 - (fm + fm2 * 4 + f2) * (p2 - mid) / 6) == 0) return tmp;
    return simpson(p1, mid) + simpson(mid, p2);
}

int main()
{
    int nr;
    double r1, r2;
    while (scanf("%d", &n) == 1)
    {
        scanf("%d%d%d%d%d", &a, &b, &c, &l, &r);
        for (int i=0;i<n;i++) scanf("%d%d", &x[i], &y[i]);
        x[n] = x[0]; y[n] = y[0]; x[n+1] = x[1]; y[n+1] = y[1];

        tot = 0;
        for (int i=0;i<n;i++) get(x[i], y[i], x[i+1], y[i+1]);
        for (int i=1;i<=n;i++)
        {
            double x1 = (x[i-1] - x[i]) * 1e-3 + x[i], y1 = (y[i-1] - y[i]) * 1e-3 + y[i];
            double x2 = (x[i+1] - x[i]) * 1e-3 + x[i], y2 = (y[i+1] - y[i]) * 1e-3 + y[i];
            if (dcmp(func(x1) - y1) * dcmp(func(x2) - y2) < 0) p[tot++] = x[i];
        }

        sort(p, p+tot);
        double ans = 0;
        tot--;
        for (int i=0;i<tot;i++)
            if (!(i&1)) ans += simpson(max((double)l, p[i]), min((double)r, p[i+1]));
        printf("%.2lf\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值