HDU2892 求多边形与圆相交面积

通过物理与计算几何原理,计算炸弹爆炸对不规则多边形岛屿造成的破坏面积。

传送门:HDU2892

area

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1023    Accepted Submission(s): 407


Problem Description
小白最近被空军特招为飞行员,参与一项实战演习。演习的内容是轰炸某个岛屿。。。
作为一名优秀的飞行员,任务是必须要完成的,当然,凭借小白出色的操作,顺利地将炸弹投到了岛上某个位置,可是长官更关心的是,小白投掷的炸弹到底摧毁了岛上多大的区域?
岛是一个不规则的多边形,而炸弹的爆炸半径为R。
小白只知道自己在(x,y,h)的空间坐标处以(x1,y1,0)的速度水平飞行时投下的炸弹,请你计算出小白所摧毁的岛屿的面积有多大. 重力加速度G = 10.
 

Input
首先输入三个数代表小白投弹的坐标(x,y,h);
然后输入两个数代表飞机当前的速度(x1, y1);
接着输入炸弹的爆炸半径R;
再输入一个数n,代表岛屿由n个点组成;
最后输入n行,每行输入一个(x',y')坐标,代表岛屿的顶点(按顺势针或者逆时针给出)。(3<= n < 100000)
 

Output
输出一个两位小数,表示实际轰炸到的岛屿的面积。
 

Sample Input

 
0 0 2000 100 0 100 4 1900 100 2000 100 2000 -100 1900 -100
 

Sample Output

 
15707.96


分析:题意很清楚了,没啥坑点,直接说思路

先根据简单的初中物理牛顿力学的知识求出圆心位置。。

以圆心和多边形两个相邻的顶点构成三角形,一共有n个这样的三角形。

求每个三角形与圆相交的面积,累加求和。


分三种情况:

case1: 两点都在圆内,相交面积即为三角形面积

case2: 一个点在圆内,一个在外部,相交面积为小三角形面积+扇形面积

case3:

两点在圆外,线段与圆交点小于2时,相交面积为扇形面积

等于2,相交面积为大扇形面积-小扇形面积+小三角形面积


利用叉积可以求出三角形面积

扇形面积公式为 ang*R*R*0.5, ang为扇形所对应的圆心角


程序参考了蓝书的模板

代码如下:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;

const double eps = 1e-8;
int dcmp(double x){
   if (fabs(x)<eps) return 0;
   return x<0?-1:1;
}

struct Point{
   double x,y;
   Point (double x=0, double y=0):x(x),y(y){}
};

typedef Point Vector;

Vector operator +(Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y); }
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }
Vector operator *(Vector A,double p) {return Vector(A.x*p,A.y*p); }

double Dot(Vector A,Vector B) { return A.x*B.x+A.y*B.y;}
double Cross(Vector A,Vector B) {return A.x*B.y-A.y*B.x;}
double Length(Vector A) {return sqrt(Dot(A,A));}
double Angle(Vector A,Vector B) { return acos(Dot(A,B)/Length(A)/Length(B));}

bool OnSegment(Point p, Point a1, Point a2){
   return dcmp(Cross(a1-p,a2-p))==0 && dcmp(Dot(a1-p,a2-p))<=0;
}

double DistanceToLine(Point p, Point a, Point b){
   Vector v1 = b-a, v2 = p-a;
   return fabs(Cross(v1,v2))/Length(v1);
}

struct Line{
    Point p;
    Vector v;
    Line(){}
    Line(Point p,Vector v):p(p),v(v){}
    Point point(double t){
       return p+v*t;
    }
};

struct Circle{
    Point c;
    double r;
    Circle(){}
    Circle(Point c, double r):c(c),r(r){}
};

int getLineCircleIntersection(Line L,Circle C, vector<Point>& sol){
    double a = L.v.x, b = L.p.x-C.c.x, c = L.v.y, d = L.p.y-C.c.y;
    double e = a*a+c*c, f = 2*(a*b+c*d), g = b*b+d*d-C.r*C.r;
    double delta = f*f-4*e*g;
    if (dcmp(delta)<0)  return 0;

    double t1,t2;
    if (dcmp(delta)==0) {
        t1 = t2 = -f/(2*e);
        sol.push_back(L.point(t1));
        return 1;
    }

    t1 = (-f-sqrt(delta))/(2*e); sol.push_back(L.point(t1));
    t2 = (-f+sqrt(delta))/(2*e); sol.push_back(L.point(t2));
    return 2;
}

double get_Circle_polygon_Intersect_area(Point A, Point B,Circle C){
    Vector CA = C.c-A, CB = C.c-B;
    double da = Length(CA), db = Length(CB);

    da = dcmp(da-C.r);
    db = dcmp(db-C.r);

    if (da<=0 && db<=0) {
        return fabs(Cross(CA,CB))*0.5;
    }

    vector<Point>sol;
    int num = getLineCircleIntersection(Line(A,B-A),C,sol);
    double cnt = C.r*C.r;
    Point q;

    if (da<=0 && db>0) {
        q = OnSegment(sol[0],A,B)?sol[0]:sol[1];
        double area = fabs(Cross(CA,C.c-q))*0.5;
        double ang = Angle(CB,C.c-q);
        return area+cnt*ang*0.5;
    }

    if (db<=0 && da>0) {
        q = OnSegment(sol[0],A,B)?sol[0]:sol[1];
        double area = fabs(Cross(CB,C.c-q))*0.5;
        double ang = Angle(CA,C.c-q);
        return area+cnt*ang*0.5;
    }

    if (num==2) {
        double big_area = cnt*Angle(CA,CB)*0.5;
        double small_area = cnt*Angle(C.c-sol[0],C.c-sol[1])*0.5;
        double delta_area = fabs(Cross(C.c-sol[0],C.c-sol[1]))*0.5;
        return big_area+delta_area-small_area;
    }

    return cnt*Angle(CA,CB)*0.5;
}

Circle bomb;
double X1,Y1,R;
double X0,Y0,h;
double x,y;
const int maxn = 100000+5;
Point p[maxn];
int n;

int main(){
    while (scanf("%lf%lf%lf",&X0,&Y0,&h)==3){
        scanf("%lf%lf",&X1,&Y1);
        scanf("%lf",&R);
        double t = sqrt(0.2*h);
        bomb = Circle(Point(X0+X1*t,Y0+Y1*t),R);

        scanf("%d",&n);
        for (int i=0; i<n; i++) {
            scanf("%lf%lf",&x,&y);
            p[i] = Point(x,y);
        }
        p[n] = p[0];

        double area = 0;
        for (int i=0; i<n; i++) {
             double tmp = get_Circle_polygon_Intersect_area(p[i],p[i+1],bomb);
             if (Cross(p[i]-bomb.c,p[i+1]-bomb.c)<0) tmp = -tmp;
             area += tmp;
        }

        if (area<0) area = -area;
        printf("%.2f\n",area);
    }
    return 0;
}


心得:

很久以前做过这题,当时计算几何知识没有系统的学习,做这题完全是照抄别人的板子。现在回想起来实在太傻了,自己骗自己很优秀,又会了点东西。其实啥都没学会。模板是死的,题目是活的。下次碰到情景变换的题目可能就写不出来了。

当时觉得这题好难,自己的码力也跟不上去。现在看这题就是水题了,没啥难度。有空多看看书,多看看论文,好好琢磨程序为什么这么写。搞懂算法原理才是真,做题数量啥的都是虚。

学习不应浮躁,沉下心来慢慢啃,基础打扎实了才能有长足的进步。



内容概要:本文系统梳理了多个科研领域的前沿研究与技术实现,重点涵盖FDTD方法中的完美匹配层(PML)研究,以及Matlab/Simulink在电磁、电力、控制、通信、信号处理、图像处理、路径规划、能源系统优化等领域的仿真与算法实现。文中列举了大量基于Matlab和Python的科研案例,如风电功率预测、负荷预测、无人机三维路径规划、电池系统故障诊断、雷达模拟、通信编码、微电网优化调度等,并强调结合智能优化算法(如粒子群、遗传算法、深度学习等)提升系统性能。同时,提供了丰富的代码资源与仿真模型,涵盖永磁同步电机控制、逆变器设计、多智能体任务分配、虚拟电厂调度等复杂系统,助力科研人员快速开展复现实验与创新研究。; 适合人群:具备一定编程基础,熟悉Matlab/Python工具,从事电气工程、自动化、通信、人工智能、新能源、控制科学等相关领域研究的研发人员及研究生。; 使用场景及目标:① 学习并实现FDTD仿真中的PML边界条件以有效抑制数值反射;② 掌握Matlab/Simulink在多物理场建模、控制系统设计与优化算法中的综合应用;③ 借助提供的代码资源完成科研复现、课程设计、竞赛项目或工程原型开发; 阅读建议:此资源以科研实战为导向,不仅提供理论方法,更强调代码实现与仿真验证。建议读者结合自身研究方向,按目录顺序查阅相关模块,下载配套代码进行调试与二次开发,以达到学以致用、融会贯通的目的。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值