【YBT2023寒假Day14 A】切割蛋糕(计算几何)

切割蛋糕

题目链接:YBT2023寒假Day14 A

题目大意

给你一个圆,圆心在原点,每次有一条直线,切掉圆中不包含原点的部分。
(直线给出的部分是它在于圆两个交点形成的线段的垂直平分线跟 x 正半轴的角度和这条直线跟垂直平分线交点到源点的距离)
然后最后问你剩下的那个图形圆弧部分的长度和与直线部分的长度和。

思路

不难想到可以直接上半平面交然后随便做(圆拆成很多条直线就行)
但我半平面写挂了,用一个别的好写写法。

首先你可以算出每条直线它与圆的两个交点,分别在圆上的角度。
那我们可以算出没有被切去的圆弧的长度了。

然后至于算直线,我可以枚举每一个直线,看它被保留了多少。
(一开始是它跟圆两个交点的距离)
那看保留我们就枚举别的直线,找到交点分别属于这个直线的两边的,然后算两个直线的交点,更改保留的部分。
不难想到保留的部分一定是一个区间,因为每次保留(或者删去)的部分都是一个你直线的一个前缀或者后缀。
那把每个直线保留的长度加上就是直线的答案了。

代码

#include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int N = 55; const double Pi = acos(-1.0); struct dian { double x, y; }a[N], b[N]; int n, m, l[N], r[N]; double RR, L[N], R[N], p[N], val[N]; bool in[N], no[N]; dian operator +(dian x, dian y) { return (dian){x.x + y.x, x.y + y.y}; } dian operator -(dian x, dian y) { return (dian){x.x - y.x, x.y - y.y}; } dian operator *(dian x, double y) { return (dian){x.x * y, x.y * y}; } double operator *(dian x, dian y) { return x.x * y.x + x.y * y.y; } double operator ^(dian x, dian y) { return x.x * y.y - x.y * y.x; } struct line { dian x, y; }; dian Meet(line a, line b) { double k = ((b.y - b.x) ^ (a.x - b.x)) / ((a.y - a.x) ^ (b.y - b.x)); return a.x + (a.y - a.x) * k; } dian Meet(dian ax, dian ay, dian bx, dian by) { double k = ((by - bx) ^ (ax - bx)) / ((ay - ax) ^ (by - bx)); return ax + (ay - ax) * k; } double dis(dian x, dian y) { return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y)); } int main() { freopen("cake.in", "r", stdin); freopen("cake.out", "w", stdout); scanf("%d %lf", &n, &RR); for (int i = 1; i <= n; i++) { double A, h; scanf("%lf %lf", &A, &h); A = A / 180 * Pi; double B = acos(h / RR); L[i] = A - B; R[i] = A + B; while (L[i] < 0) L[i] += 2 * Pi; while (R[i] >= 2 * Pi) R[i] -= 2 * Pi; p[++m] = L[i]; p[++m] = R[i]; a[i] = (dian){cos(L[i]), sin(L[i])}; b[i] = (dian){cos(R[i]), sin(R[i])}; } sort(p + 1, p + m + 1); m = unique(p + 1, p + m + 1) - p - 1; double ans1 = 0, ans2 = 2 * Pi; for (int i = 1; i <= n; i++) { l[i] = lower_bound(p + 1, p + m + 1, L[i]) - p;//离散化 r[i] = lower_bound(p + 1, p + m + 1, R[i]) - p; for (int j = l[i]; j != r[i]; j = j % m + 1) { if (in[j]) continue; in[j] = 1; double x = p[j % m + 1] - p[j]; while (x < 0) x += 2 * Pi; ans2 -= x; } } for (int i = 1; i <= m; i++) in[i] = 0; for (int i = 1; i <= n; i++) { for (int j = l[i]; j != r[i]; j = j % m + 1) in[j] = 1; double ls = 0, rs = dis(a[i], b[i]); for (int j = 1; j <= n; j++) { if (i == j) continue; if (!in[l[j]] && !in[r[j]]) continue; if (in[l[j]] && in[r[j]]) {//这条直线的作用被完全代替 no[j] = 1; continue; } double awa = dis(Meet(a[i], b[i], a[j], b[j]), a[i]); if (in[l[j]]) rs = min(rs, awa); else ls = max(ls, awa); } if (ls <= rs) val[i] = rs - ls; for (int j = l[i]; j != r[i]; j = j % m + 1) in[j] = 0; } for (int i = 1; i <= n; i++) { if (no[i]) continue; ans1 += val[i]; } printf("%.10lf %.10lf", ans1 * RR, ans2 * RR); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day14_A.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2022-02-24 【2022 省选训练赛 Contest 05 C】B(计算几何)
2022-02-24 【2022 省选训练赛 Contest 05 B】卷积练习题(暴力)(性质)
2022-02-24 【2022 省选训练赛 Contest 05 A】tree(树形DP)
2021-02-24 【ybt金牌导航6-5-1】【luogu P3810】【模板】三维偏序(陌上花开)
2021-02-24 【ybt金牌导航6-4-1】区间不同数 / 莫队例题
2021-02-24 【ybt金牌导航6-3-1】【luogu P4168】区间众数 / 蒲公英 / 分块例题
2021-02-24 【ybt金牌导航6-2-1】【luogu P3201】梦幻布丁 / 启发式合并例题
点击右上角即可分享
微信分享提示