1 条题解
-
0
题意分析
解题思路
-
采用回溯法来尝试所有可能的中继站组合。
-
定义函数计算两个圆的重叠面积(intersectionArea):根据两圆的圆心距 与两圆半径的关系,分情况计算重叠面积。若d ≥a.r + b.r,两圆不重叠,重叠面积为(0);若d ≤ |a.r - b.r|,一个圆完全包含在另一个圆内,重叠面积为较小圆的面积;否则通过余弦定理计算圆心角,进而算出重叠面积。
-
定义函数计算总覆盖面积(calculateTotalArea):先将基站面积加入总面积,然后对每个选中的中继站,加上其面积,并减去该中继站与基站以及已选中中继站之间的重叠面积。
-
在回溯函数(backtrack)中,对于每个候选中继站,分别考虑选和不选两种情况。选的时候,检查该中继站与已选的中继站是否不相交(通过比较圆心距与半径和),若不相交则将其加入已选集合,继续递归;不选则直接递归下一个中继站。每次递归结束后,更新最大覆盖面积。
分析
实现步骤
代码实现
#include <iostream> #include <iomanip> #include <cmath> #include <vector> using namespace std; const double PI = acos(-1.0); const double EPS = 1e-9; struct Station { double x, y, r; }; // 计算两个圆的重叠面积 double intersectionArea(Station a, Station b) { double d = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); if (d >= a.r + b.r) return 0; if (d <= fabs(a.r - b.r)) return PI * min(a.r, b.r) * min(a.r, b.r); double cosAlpha = (a.r * a.r + d * d - b.r * b.r) / (2 * a.r * d); double alpha = acos(cosAlpha); double cosBeta = (b.r * b.r + d * d - a.r * a.r) / (2 * b.r * d); double beta = acos(cosBeta); double sectorA = a.r * a.r * alpha; double triangleA = a.r * a.r * sin(alpha) * cosAlpha; double sectorB = b.r * b.r * beta; double triangleB = b.r * b.r * sin(beta) * cosBeta; return sectorA + sectorB - triangleA - triangleB; } // 计算当前选择的基站和中继站的总覆盖面积 double calculateTotalArea(Station base, const vector<Station>& selected) { double total = PI * base.r * base.r; for (int i = 0; i < selected.size(); ++i) { total += PI * selected[i].r * selected[i].r; total -= intersectionArea(base, selected[i]); for (int j = 0; j < i; ++j) { total -= intersectionArea(selected[i], selected[j]); } } return total; } // 回溯法尝试所有可能的中继站组合 void backtrack(int index, Station base, const vector<Station>& candidates, vector<Station>& selected, double& maxArea) { if (index == candidates.size()) { maxArea = max(maxArea, calculateTotalArea(base, selected)); return; } // 不选择当前中继站 backtrack(index + 1, base, candidates, selected, maxArea); // 检查当前中继站是否与已选的中继站不相交 bool canSelect = true; for (const auto& s : selected) { if (sqrt((s.x - candidates[index].x) * (s.x - candidates[index].x) + (s.y - candidates[index].y) * (s.y - candidates[index].y)) < s.r + candidates[index].r - EPS) { canSelect = false; break; } } if (canSelect) { selected.push_back(candidates[index]); backtrack(index + 1, base, candidates, selected, maxArea); selected.pop_back(); } } int main() { int N; double x0, y0, R; cin >> N >> x0 >> y0 >> R; Station base = {x0, y0, R}; vector<Station> candidates(N); for (int i = 0; i < N; ++i) { cin >> candidates[i].x >> candidates[i].y >> candidates[i].r; } vector<Station> selected; double maxArea = 0; backtrack(0, base, candidates, selected, maxArea); cout << fixed << setprecision(4) << maxArea << endl; return 0; }
代码说明
-
头文件和常量定义:
(1)包含了输入输出流()、精度设置()、数学函数()和向量容器()的头文件。
(2)定义了常量(PI)(通过(acos(-1.0))计算圆周率)和(EPS)(用于比较浮点数时的精度误差,值为(1e - 9))。
-
结构体定义:Station结构体用于存储基站和中继站的信息,包括坐标(x)、(y)和半径(r)。
-
intersectionArea函数:计算两个圆的重叠面积,根据圆心距与半径的关系分情况讨论,运用余弦定理和三角函数计算重叠部分的扇形和三角形面积,进而得到重叠面积。
-
calculateTotalArea函数:计算当前选择的基站和中继站的总覆盖面积,先加上基站面积和各中继站面积,再减去基站与中继站、中继站之间的重叠面积。
-
backtrack函数:回溯法的核心函数,递归地尝试所有可能的中继站组合。对于每个候选中继站,分别考虑选和不选的情况,选的时候检查是否与已选的中继站相交,若不相交则加入已选集合并继续递归,最后更新最大面积。
-
main函数:读取输入数据,初始化基站和候选中继站信息,调用回溯函数计算最大覆盖面积,并输出结果,设置输出精度为小数点后(4)位。
-
- 1
信息
- ID
- 1383
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者