题目描述
输入格式
输出格式
输入输出样例
输入 #1复制
12 3 3 4 6 4 11 4 8 10 6 5 7 6 6 6 3 7 9 10 4 10 9 1 7 5 20 20 20 40 40 20 40 40 30 30 3 10 10 21 10 21 13 -1 5 5 20 12
输出 #1复制
70.50
题目大意:(自己翻译的)
给你一堆城市,每个城市由一堆点构成,城市的围墙是包含这个城市所有点的最小多边形,城市之间两两不相交。然后有给出一堆导弹的坐标,若一个导弹打在某个城市内部即可摧毁这个城市,问导弹摧毁的城市的总面积。
这是一道运用面积算法的计算几何题。
对于给定的炮台坐标和攻击半径 D,题目要求计算平面内有多少点不能被该炮台中心覆盖到,则可以使用面积差计算得出。因为该问题较难分别处理不同半径情况,所以建议所有炮台都瞄准同样的半径进行计算。
具体来说,我们可以利用每个圆的面积减去它们之间重叠区域的面积以求得最终答案。
操作步骤如下:
- 首先,定义一个常量
PI
表示圆周率 π。利用该常量与圆形半径进行面积计算。 - 对于相邻两个圆,若相交,就需要计算出这两个圆重叠段的面积,也就是求出图中的深色部分的面积。
- 所有的嵌套在大圆内的小圆面积相加是求得的全部被覆盖的区域,即炮台能够覆盖的面积。
- 最终剩余的面积表示炮台不能覆盖(或者只有部分覆盖)的区域。
- 注意由于测试用例不是很严格,不一定正确,所以在编写代码时可能需要做出更多的判断(例如半径为负数等异常情况),以避免意外情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double EPS = 1e-8, pi = acos(-1);
struct Point {
double x, y;
Point(double _x = 0, double _y = 0) : x(_x), y(_y) {}
Point operator+(Point v) { return { x + v.x, y + v.y }; }
Point operator-(Point v) { return { x - v.x, y - v.y }; }
double operator*(Point v) { return x * v.y - y * v.x; } // 叉积
};
int n;
Point a[105];
double r[105];
double dist(Point A, Point B) {
return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
double sector(double R, double angle) {
return R * R * (angle - sin(angle)) / 2.0;
}
double solve(int i, int j) {
if (dist(a[i], a[j]) <= r[i] - r[j] + EPS) { // 包含关系
return pi * r[j] * r[j];
} else if (dist(a[i], a[j]) >= r[i] + r[j] - EPS) { // 两圆外离
return 0;
} else {
double d = dist(a[i], a[j]);
double a1 = acos((r[i] * r[i] + d * d - r[j] * r[j]) / (2.0 * r[i] * d));
double a2 = acos((r[j] * r[j] + d * d - r[i] * r[i]) / (2.0 * r[j] * d));
double area1 = sector(r[i], a1) - 0.5 * r[i] * r[i] * sin(2 * a1);
double area2 = sector(r[j], a2) - 0.5 * r[j] * r[j] * sin(2 * a2);
return area1 + area2;
}
}
double check(double R) { // 计算半径为R的超圆和几何图形的部分面积
double ans = 0, curr;
for (int i = 0; i < n; i++) {
curr = pi * r[i] * r[i];
for (int j = 0; j < i; j++) {
curr -= solve(i, j); //减去与其他圆被覆盖的面积
}
ans += ((i & 1)?-1:1) * curr; // 奇数个相减,偶数个相加
}
return ans;
}
int main() {
while (cin >> n && n != -1) {
for (int i = 0; i < n; i++) {
cin >> a[i].x >> a[i].y >> r[i];
}
double L = 0, R = 3000, mid;
while (R - L >= EPS) {
mid = (L + R) / 2.0;
if (check(mid) < 0) L = mid;
else R = mid;
}
cout << fixed << setprecision(2) << R << endl;
}
return 0;
}
0