给你一个凸多边形,然后你要在这个凸多边形里面选一个点,要这个点满足它跟每个凸多边形的端点连边,构成的若干个三角形中面积最小的是跟 0 号点 1 号点构成的三角形。 问你选的点合法的概率。
[SCOI2015]小凸想跑步 / convex
题目大意
给你一个凸多边形,然后你要在这个凸多边形里面选一个点,要这个点满足它跟每个凸多边形的端点连边,构成的若干个三角形中面积最小的是跟 0 号点 1 号点构成的三角形。
问你选的点合法的概率。
思路
我们其实会想到满足的点应该是构成了一个 0,1 号点为其中一个边缘的一个多边形。
然后那概率就是这个多边形的面积除以整个多边形的面积,那问题就是怎么找这个多边形。
我们考虑它和其它边的优劣关系,那列出若干个式子我们要它们都满足,那其实会想到可能是半平面交。
考虑列式子出来。
→ab×−→ao<→cd×→co(o 点的 x,y 坐标直接用 x,y 表示)
(xb−xa)(y−ya)−(yb−ya)(x−xa)<(xd−xc)(y−yc)−(yd−yc)(x−xc)
(xb−xa)(y−ya)+(yd−yc)(x−xc)−(yb−ya)(x−xa)−(xd−xc)(y−yc)<0
(ya−yb−yc+yd)x−(xa−xb−xc+xd)y+(ybxa−xbya+xdyc−ydxc)<0
设 (ya−yb−yc+yd)=a,(xa−xb−xc+xd)=b,(ybxa−xbya+xdyc−ydxc)=c
ax−by+c<0
by<−ax−c
然后你会发现它这个是一条直线的一边,所以就可以愉快的用半平面交啦。
代码
#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() {
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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现