Solution -「SPOJ-VCIRCLES」Area of Circles
Link.
求平面上 个圆的并的面积。
,可能被圆覆盖的横纵坐标区域在 。
做了那么多计算几何之后写了这道不那么计算几何的计算几何题的题解。
若想直接处理面积,就需要处理圆的各种相交关系,但是仅计算在某个 处,被圆的并覆盖的线段长度是很好处理地:每次 排序后扫一遍即可。我们记 表示 时,被圆的并覆盖的线段长度。所以问题转为求 。
运用自适应 Simpson 积分,有 Simpson 公式:
其本质是用二次函数 近似地替换一个复杂的函数 ,即设:
利用 化简积分,注意 仅是一种形式,我们的目的使用 的一些点值近似表示原积分。推导:
记 ,自适应 Simpson 积分的表达式如下:
其中 根据题目精度要求等自行判断。若精度不合适,则递归求解提升精确度。
注意自适应 Simpson 积分只能处理平滑函数。例如依照上述算法,(大雾)。
回到本题,结合求 求 的方法近似求出 即可。复杂度与圆的位置和要求精度有关(aka. 我不知道 qwq)。
讲道理若某两块并在 轴上的投影相离应该分开求积分,但那样写我 WA 掉了 qwq。
/* Clearink */
#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>
typedef std::pair<double, double> PDD;
const int MAXN = 50;
const double EPS = 1e-9;
int n;
bool ban[MAXN + 5];
inline double sqr ( const double a ) { return a * a; }
inline double dabs ( const double a ) { return a < 0 ? -a : a; }
inline double dmin ( const double a, const double b ) { return a < b ? a : b; }
inline double dmax ( const double a, const double b ) { return a < b ? b : a; }
struct Circle { double x, y, r; } O[MAXN + 5];
inline double func ( const double x ) {
static std::vector<PDD> sec; sec.clear ();
for ( int i = 1; i <= n; ++i ) {
const Circle& C ( O[i] );
if ( dabs ( x - C.x ) < C.r ) {
double yd = sqrt ( sqr ( C.r ) - sqr ( dabs ( C.x - x ) ) );
sec.push_back ( { C.y - yd, C.y + yd } );
}
}
std::sort ( sec.begin (), sec.end () );
double las = -1e9, ret = 0;
for ( PDD s: sec ) {
las = dmax ( las, s.first );
ret += dmax ( 0, s.second - las );
las = dmax ( las, s.second );
}
return ret;
}
inline double scalc ( const double lx, const double rx,
const double fl, const double fm, const double fr ) {
return ( fl + 4 * fm + fr ) / 6 * ( rx - lx );
}
inline double simpson ( const double lx, const double rx,
const double fl, const double fm, const double fr ) {
double mx = 0.5 * ( lx + rx );
double fll = func ( 0.5 * ( lx + mx ) ), frr = func ( 0.5 * ( mx + rx ) );
double s = scalc ( lx, rx, fl, fm, fr );
double sl = scalc ( lx, mx, fl, fll, fm ), sr = scalc ( mx, rx, fm, frr, fr );
if ( dabs ( s - sl - sr ) < EPS ) return sl + sr;
return simpson ( lx, mx, fl, fll, fm ) + simpson ( mx, rx, fm, frr, fr );
}
int main () {
scanf ( "%d", &n );
double mn = 1e9, mx = -1e9;
for ( int i = 1; i <= n; ++i ) {
scanf ( "%lf %lf %lf", &O[i].x, &O[i].y, &O[i].r );
mn = dmin ( mn, O[i].x - O[i].r );
mx = dmax ( mx, O[i].x + O[i].r );
}
printf ( "%.5f\n", simpson ( mn, mx,
func ( mn ), func ( 0.5 * ( mn + mx ) ), func ( mx ) ) );
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现