http://acm.hdu.edu.cn/showproblem.php?pid=2892
解题思路:
求多边形与圆的相交的面积是多少。
以圆心为顶点,将多边形划分为n个三角形。
接下来就求出每个三角形与圆相交的面积。
因为三角形的一个点是圆心,所以三角形的另外两个点与圆的情况有以下几种:
(1)两点都在圆里,三角形与圆相交的面积=三角形的面积。
(2)一个点在圆外,一个点在圆里,三角形与圆相交的面积=小三角形的面积+扇形面积
(3)两点都在圆外,又分为几种情况:
1、两点构成的线段与圆相交的点数0或1个时,三角形与圆相交的面积=扇形的面积
2.两点构成的线段与圆相交的点数2个时,三角形与圆相交的面积=大扇形面积+小三角形面积-小扇形的面积
1 #include<cmath> 2 #include<cstdio> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 7 #define MAXN 100000+10 8 #define PI acos(-1.0) 9 #define EPS 0.00000001 10 11 int dcmp(double x){ 12 if(fabs(x) < EPS) 13 return 0; 14 return x < 0 ? -1 : 1; 15 } 16 17 struct Point{ 18 double x, y; 19 Point(double x = 0, double y = 0): x(x), y(y) {} 20 }; 21 22 struct Circle{ 23 Point c; 24 double r; 25 Circle(Point c = Point(0, 0), double r = 0): c(c), r(r) {} 26 }; 27 28 typedef Point Vector; 29 30 Vector operator + (Vector A, Vector B){ 31 return Vector(A.x + B.x, A.y + B.y); 32 } 33 Vector operator - (Point A, Point B){ 34 return Vector(A.x - B.x, A.y - B.y); 35 } 36 Vector operator * (Vector A, double p){ 37 return Vector(A.x * p, A.y * p); 38 } 39 Vector operator / (Vector A, double p){ 40 return Vector(A.x / p, A.y / p); 41 } 42 43 double dot(Vector A, Vector B){ 44 return A.x * B.x + A.y * B.y; 45 } 46 47 double length(Vector A){ 48 return sqrt(dot(A, A)); 49 } 50 51 double angle(Vector A, Vector B){ 52 return acos(dot(A, B) / length(A) / length(B)); 53 } 54 55 double cross(Vector A, Vector B){ 56 return A.x * B.y - A.y * B.x; 57 } 58 59 Circle bomb;//炸弹爆炸的坐标及半径 60 Point p[MAXN];//岛屿的点 61 int n;//岛屿点数 62 63 double point_line_distance(Point P, Point A, Point B){//点到直线的距离 64 Vector AP = P - A, AB = B - A; 65 return fabs(cross(AP, AB) / length(AB)); 66 } 67 68 Point point_line_projection(Point P, Point A, Point B){//点在直线上的映射 69 Vector v = B - A; 70 return A + v * (dot(v, P - A) / dot(v, v)); 71 } 72 73 int circle_line_intersect(Circle C, Point A, Point B, vector<Point> &v){ 74 double dist = point_line_distance(C.c, A, B); 75 int d = dcmp(dist - C.r); 76 if(d > 0){ 77 return 0; 78 } 79 Point pro = point_line_projection(C.c, A, B); 80 if(d == 0){ 81 v.push_back(pro); 82 return 1; 83 } 84 double len = sqrt(C.r * C.r - dist * dist);//勾股定理 85 Vector AB = B - A; 86 Vector l = AB / length(AB) * len; 87 v.push_back(pro + l); 88 v.push_back(pro - l); 89 return 2; 90 } 91 92 bool point_on_segment(Point P, Point A, Point B){//判断点在线段上 93 Vector PA = A - P, PB = B - P; 94 return dcmp(cross(PA, PB)) == 0 && dcmp(dot(PA, PB)) <= 0; 95 } 96 97 double circle_delta_intersect_area(Circle C, Point A, Point B){ 98 Vector CA = A - C.c, CB = B - C.c; 99 double da = length(CA), db = length(CB); 100 101 da = dcmp(da - C.r), db = dcmp(db - C.r); 102 103 if(da <= 0 && db <= 0){//三角形在圆里面 104 return fabs(cross(CA, CB)) * 0.5; 105 } 106 107 vector<Point> v; 108 int num = circle_line_intersect(C, A, B, v);//圆和直线的关系 109 double carea = C.r * C.r * PI; 110 Point t; 111 if(da <= 0 && db > 0){//左边的点在圆里 右边的点在圆外 112 t = point_on_segment(v[0], A, B) ? v[0] : v[1]; 113 114 double area = fabs(cross(CA, t - C.c)) * 0.5, an = angle(CB, t - C.c); 115 return area + carea * an / PI / 2; 116 } 117 if(da > 0 && db <= 0){//左边点在圆外 右边点在圆里 118 t = point_on_segment(v[0], A, B) ? v[0] : v[1]; 119 120 double area = fabs(cross(CB, t - C.c)) * 0.5, an = angle(CA, t - C.c); 121 return area + carea * an / PI / 2; 122 } 123 //两个点都在圆外 124 if(num == 2){ 125 double bigarea = carea * angle(CA, CB) / PI / 2, 126 smallarea = carea * angle(v[0] - C.c, v[1] - C.c) / PI / 2, 127 deltaarea = fabs(cross(v[0] - C.c, v[1] - C.c)) * 0.5; 128 return bigarea + deltaarea - smallarea; 129 } 130 return carea * angle(CA, CB) / PI / 2;//两点都在圆外 直线AB与圆交点1个或两个 131 } 132 133 double circle_polygon_intersect_area(){//源于多边形相交面积 134 p[n] = p[0]; 135 double ans = 0; 136 for(int i = 0; i < n; i++ ){ 137 double area = circle_delta_intersect_area( bomb, p[i], p[i + 1] ); 138 if(cross(p[i] - bomb.c, p[i + 1] - bomb.c) < 0){ 139 area = -area; 140 } 141 ans += area; 142 } 143 return ans > 0 ? ans : -ans; 144 } 145 146 void solve(){ 147 scanf("%d", &n ); 148 for(int i = 0; i < n; i++ ){ 149 scanf("%lf%lf", &p[i].x, &p[i].y ); 150 } 151 printf("%.2lf\n", circle_polygon_intersect_area() ); 152 } 153 154 int main(){ 155 //freopen("data.in", "r", stdin ); 156 double x, y, h, x1, y1, r; 157 while(~scanf("%lf%lf%lf", &x, &y, &h )){ 158 scanf("%lf%lf%lf", &x1, &y1, &r ); 159 160 double t = sqrt(0.2 * h);//h = 0.5 * G * t^2 重力加速度公式 161 162 bomb = Circle( Point(x1 * t + x, y1 * t + y), r ); 163 164 solve(); 165 } 166 return 0; 167 }
hdu 2892 Area
时间: 2025-01-10 16:13:39