【luogu P4250】【bzoj 4445】【LOJ 2008】【2022 省选训练赛 Contest 15 B】[SCOI2015]小凸想跑步 / convex(半平面交)

[SCOI2015]小凸想跑步 / convex

题目链接:luogu P4250 / bzoj 4445 / LOJ 2008 / 2022 省选训练赛 Contest 15 B

题目大意

给你一个凸多边形,然后你要在这个凸多边形里面选一个点,要这个点满足它跟每个凸多边形的端点连边,构成的若干个三角形中面积最小的是跟 0 号点 1 号点构成的三角形。
问你选的点合法的概率。

思路

我们其实会想到满足的点应该是构成了一个 0,1 号点为其中一个边缘的一个多边形。
然后那概率就是这个多边形的面积除以整个多边形的面积,那问题就是怎么找这个多边形。
我们考虑它和其它边的优劣关系,那列出若干个式子我们要它们都满足,那其实会想到可能是半平面交。

考虑列式子出来。
ab×ao<cd×coo 点的 x,y 坐标直接用 x,y 表示)
(xbxa)(yya)(ybya)(xxa)<(xdxc)(yyc)(ydyc)(xxc)
(xbxa)(yya)+(ydyc)(xxc)(ybya)(xxa)(xdxc)(yyc)<0
(yaybyc+yd)x(xaxbxc+xd)y+(ybxaxbya+xdycydxc)<0
(yaybyc+yd)=a,(xaxbxc+xd)=b,(ybxaxbya+xdycydxc)=c
axby+c<0
by<axc

然后你会发现它这个是一条直线的一边,所以就可以愉快的用半平面交啦。

代码

#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define db long double using namespace std; const int N = 200000 + 100; const db eps = 1e-14; struct node { db x, y; }G[N], a[N]; node operator +(node x, node y) { return (node){x.x + y.x, x.y + y.y}; } node operator -(node x, node y) { return (node){x.x - y.x, x.y - y.y}; } db operator *(node x, node y) { return x.x * y.x + x.y * y.y; } db operator ^(node x, node y) { return x.x * y.y - x.y * y.x; } node operator *(node x, db y) { return (node){x.x * y, x.y * y}; } struct line { node x, y; db k; line() {} line (node xx, node yy) { x = xx; y = yy; k = atan2((y - x).y, (y - x).x); } }L[N << 1]; int n, tot, q[N]; db Area_clac(node *G, int l, int r) { db re = 0; for (int i = l + 1; i < r; i++) re += (G[i] - G[l]) ^ (G[i + 1] - G[l]); return fabs(re / 2); } bool cmp(line x, line y) { if (fabs(x.k - y.k) > eps) return x.k < y.k; return ((y.x - x.x) ^ (x.y - y.x)) > eps;//左边的放前面 } node Meet(line a, line b) {//线段求交点 db 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; } bool check(node x, line y) { return ((x - y.x) ^ (y.y - x)) > eps; } db Halfmeet() { //去重 int tmp = 1; for (int i = 2; i <= tot; i++) if (L[i].k != L[i - 1].k) L[++tmp] = L[i]; tot = tmp; //半平面交 int l = 1, r = 0; for (int i = 1; i <= tot; i++) { while (l < r && check(G[r], L[i])) r--; while (l < r && check(G[l + 1], L[i])) l++; q[++r] = i; if (l < r) G[r] = Meet(L[q[r - 1]], L[q[r]]); } while (l < r && check(G[r], L[q[l]])) r--; while (l < r && check(G[l + 1], L[q[r]])) l++; G[l] = Meet(L[q[r]], L[q[l]]); return Area_clac(G, l, r); } int main() { // freopen("read.txt", "r", stdin); scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%Lf %Lf", &G[i].x, &G[i].y); G[n + 1] = G[1]; db sum = Area_clac(G, 1, n + 1); for (int i = 1; i <= n; i++) { L[++tot] = line(G[i], G[i + 1]); } for (int i = 2; i <= n; i++) { db a = (G[1].y - G[2].y - G[i].y + G[i + 1].y); db b = (G[2].x - G[1].x - G[i + 1].x + G[i].x); db c = (G[2].y * G[1].x - G[2].x * G[1].y + G[i + 1].x * G[i].y - G[i + 1].y * G[i].x); if (fabs(b) < eps) L[++tot] = line((node){-c / a, 0}, (node){-c / a - b, a}); else L[++tot] = line((node){0, -c / b}, (node){-b, -c / b + a}); } sort(L + 1, L + tot + 1, cmp); printf("%.4Lf", Halfmeet() / sum); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P4250.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示