HDU4404 Worms(计算多边形和圆的重叠面积)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4404

题目大意:

给出一个点的坐标,该点会做一个斜抛运动,给出点的初速度,星球的重力加速度,抛出的角度,运动时间,求该点最终到达的地方形成的圆与多边形的重叠面积。

题解:

多边形和圆的交面积模板题,以圆心为中心将多边形三角剖分,求每个三角形与圆重叠的面积。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <complex>
#define EPS 1e-9
#define MAXN 1500
using namespace std;
const double PI = acos(-1.0);

inline double sqr(double x)
{
    return x * x;
}
struct point
{
    double x,y;
    point(){}
    point(double a,double b): x(a), y (b){}
    friend point operator + (const point &a, const point &b)
    {
        return point(a.x + b.x, a.y + b.y);
    }
    friend point operator - (const point &a, const point &b)
    {
        return point(a.x - b.x, a.y - b.y);
    }

    friend point operator * (const point &a, const double &b)
    {
        return point(a.x * b, a.y * b);
    }
    friend point operator * (const double &a, const point &b)
    {
        return point(a * b.x, a * b.y);
    }
    friend point operator / (const point &a, const double &b)
    {
        return point(a.x / b, a.y/b);
    }
};
int dcmp(double k)
{
    return k < -EPS ? -1 : k > EPS ? 1 : 0;
}

double dot(const point &a, const point &b)
{
    return a.x * b.x + a.y * b.y;
}

double cross(const point &a, const point &b)
{
    return a.x * b.y - a.y * b.x;
}

double abs(const point &o)
{
    return sqrt(dot(o,o));
}
point res[MAXN];
double r;
int n;

double mysqrt(double n)
{
    return sqrt(max(0.0,n));
}

double sector_area(const point &a, const point &b)
{
    double theta = atan2(a.y, a.x) - atan2(b.y,b.x);
    while(theta <= 0)theta += 2 *PI;
    while(theta > 2 * PI)theta -= 2*PI;
    theta = min(theta, 2 * PI - theta);
    return r * r * theta/2;
}

void circleCrossLine(point a,point b, point o, double r, point ret[], int &num)
{
    double x0 = o.x,y0 = o.y;
    double x1 = a.x,y1 = a.y;
    double x2 = b.x,y2 = b.y;
    double dx = x2 - x1, dy = y2 - y1;
    double A = dx*dx + dy * dy;
    double B = 2 * dx * (x1 - x0) + 2 * dy * (y1 - y0);
    double C = sqr(x1 - x0) + sqr(y1 - y0) - sqr(r);
    double delta = B*B - 4 *A *C;
    num = 0;
    if(dcmp(delta) >= 0)
    {
        double t1 = (-B - mysqrt(delta)) / (2*A);
        double t2 = (-B + mysqrt(delta)) / (2*A);
        if(dcmp(t1 - 1) <= 0 && dcmp(t1) >= 0)
        {
            ret[num++] = point(x1 + t1 * dx, y1 + t1 * dy);
        }
        if(dcmp(t2 - 1) <= 0 && dcmp(t2) >= 0)
        {
            ret[num++] = point(x1 + t2 * dx, y1 + t2 *dy);
        }
    }
}

double calc(const point &a, const point &b)
{
    point p[2];
    int num = 0;
    int ina = dcmp(abs(a) - r) < 0;
    int inb = dcmp(abs(b) - r) < 0;
    if(ina)
    {
        if(inb)
        {
            return fabs(cross(a,b))/2.0;
        }
        else
        {
            circleCrossLine(a,b,point(0,0),r,p,num);
            return sector_area(b,p[0]) + fabs(cross(a,p[0])) / 2.0;
        }
    }
    else
    {
        if(inb)
        {
            circleCrossLine(a,b,point(0,0),r,p,num);
            return sector_area(p[0],a) + fabs(cross(p[0],b)) / 2.0;
        }
        else
        {
            circleCrossLine(a,b,point(0,0),r,p,num);
            if(num == 2)
            {
                return sector_area(a,p[0]) + sector_area(p[1],b) + fabs(cross(p[0],p[1])) / 2.0;
            }
            else
            {
                return sector_area(a,b);
            }
        }
    }
}

double area()
{
    double ret = 0;
    for(int i = 0; i < n; i++)
    {
        int sgn = dcmp(cross(res[i],res[(i+1)%n]));
        if(sgn != 0)
        {
            ret += (sgn * calc(res[i],res[(i+1)%n]));
            //cout << ret << endl;
        }
    }
    return fabs(ret);
}
double x0,y0,v0,theta,t,g;
int main()
{
    while(~scanf("%lf %lf %lf %lf %lf %lf %lf", &x0, &y0, &v0, &theta, &t, &g, &r))
    {
        if(x0 == 0 && y0 == 0 && v0 == 0 && theta == 0 && t == 0 && g ==0)break;
        //cout << x0 << " " << y0 << " " << v0 << " " << theta << " " << t << " " << g << " " << r <<endl;
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
        {
            scanf("%lf %lf",&res[i].x,&res[i].y);
        }
        double vx = v0 * cos(theta/180.0 * PI);
        double vy = v0 * sin(theta/180.0 * PI);
        //cout << vx << " " << vy << endl;
        double x = x0 + vx * t;
        double y = y0 + vy * t - 0.5 * g * t * t;
        //cout << x << " " << y << endl;
        for(int i = 0; i < n; i++)
        {
            res[i].x -= x;
            res[i].y -= y;
        }
        printf("%.2f\n",area());
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值