众所周知,国内oi比赛很不喜欢考计算几何题,尤其是一些纯解析几何题,所以平常在这方面的训练会少很多。但是国外比赛和acm比赛又经常很注重这个玩意,故收集一些这里的题。
平面计算几何初步#
向量 用一个点 (x,y) 来表示向量 →a=(x,y)。
向量的模 |→a|=√x2+y2。
向量的加减法 →a+→b=(xa+xb,ya+yb),→a−→b=(xa−xb,ya−yb)。
向量数乘 c→a=(cx,cy)。
线段长度 |AB|=|→a−→b|。
线段上一点 C=σA+(1−σ)B。
向量点积 →a⋅→b=x1x2+y1y2=|a||b|cosθ。
向量叉积 →a×→b=x1y2−x2y1,如果 →a×→b>0 说明 b 在 a 的逆时针方向。
直线 Ax+By+C=0,与 x 轴夹角的正切值 −AB。
点到直线距离 |Ax0+By0+c|√A2+B2。
圆 (x−a)2+(y−b)2=r2。
向量旋转 a′=(xcosα−ysinα,xsinα+ycosα)。
正弦定理 asinA=bsinB=csinC=2R。
余弦定理 c2=a2+b2−2abcosθ。
判断点是否在线段上 点必须在以线段为对角线的矩形里,然后叉积为 0。
点是否在任意多边形中 引出一条射线交点个数为奇数,随机化
点是否在凸多边形中,任意一条边与其中一个端点到该点的向量的叉积的正负形相同。
线段是否相交 (B−A)×(C−A) 和 (B−A)×(D−A) 不同号,且 (D−C)×(A−C) 和 (D−C)×(B−C) 不同号。
线段求交 定比分点
一些求交点,垂心的通用做法:算出边长,然后求出正切值从而得到角度,进行向量旋转。
注意,尽量不要用解析法列方程。
凸多边形 找一个点然后把凸包分成若干三角形
自适应辛普森法#
对二次函数求积分:
f(x)=ax2+bx+c∫rl=4(f(l)+f(r)+f(l+r2))6
分成若干段,每一段当二次函数处理,考虑分治,如果某一段直接算,和分成两部分算相差很小,就当做是二次函数。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
double a, b, c, d, L, R;
double F(double x) {
return (c * x + d) / (a * x + b);
}
double simpson(double l, double r) {
double mid = (l + r) / 2.0;
return (F(l) + 4 * F(mid) + F(r)) * (r - l) / 6;
}
double simpson(double l, double r, double A, double eps) {
double mid = (l + r) / 2;
double lsum = simpson(l, mid);
double rsum = simpson(mid, r);
if (fabs(lsum + rsum - A) <= eps * 15) {
return lsum + rsum + (lsum + rsum - A) / 15;
}
return simpson(l, mid, lsum, eps / 2) + simpson(mid, r, rsum, eps / 2);
}
int main() {
scanf("%lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &L, &R);
printf("%.6lf", simpson(L, R, simpson(L, R), 1e-8));
return 0;
}
格点图#
Pick Theorem
给定顶点均为整点的简单多边形,皮克定理说明了其面积 A 和内部格点数目 i、边上格点数目 b 的关系:
A=i+b2−1。
换成三角形格点:A=2i+b−2。
euler formula
V−E+F=2,其中 V 是节点数,E 是边数 F 是面数。
看成凸多面体证明显然。
凸多边形是指所有内角大小都在 [0,π] 范围内的 简单多边形。
在平面上能包含所有给定点的最小凸多边形叫做凸包。
andrew算法#
先以横坐标为第一关键字,纵坐标为第二关键字排序,然后维护下凸壳。下凸壳上的点显然是不断往左偏的,所以一旦往右偏的就只好把之前的值弹出。
graham#
找到纵坐标最小的点中横坐标最小的点作为原点,把每个点极角排序,然后按顺序加入,显然每条边都在之前的边的逆时针方向。
旋转卡壳#
求凸包直径,直径一定是对踵点对中产生,即存在两条平行切线经过的点。按顺序遍历凸包上每一条边,那这条边的对踵点也会按顺序移动。底边确定后,根据三角形面积即可算出答案。但是正方形三角形的时候会有点问题,可以考虑暴力判掉。
double ans=0;
for(int i=1,j=2;i<=top;i++){
while(((stk[i+1]-stk[i])*(stk[j]-stk[i]))<((stk[i+1]-stk[i])*(stk[j+1]-stk[i])))j=j%top+1;
ans=max(ans,dis(stk[i],stk[j]));
}
动态凸包#
闵可夫斯基和#
三角剖分#
Delaunay 三角剖分
其满足如下性质:
分治的思想:
先按横坐标排序,然后分成两个部分。这个边分成三种:LL-edge,RR-edge,LR-edge,一开始并没有 LR-edge。找到最底部的不与 LL,RR相交的LR-edge作为base-LR-edge。然后我们需要找到在其之上的一条LR-edge。考虑左端点为当前LR-edge左端点,右端点的可能集合,必须为当前base-LR-edge的右端点的RR-edge的另一端点。并且这三个点所成的圆不能包含其他可能点。左侧同理。
如果左右都有可能点,选择那个不会包含另一个的点。显然这样的点只会有一个。否则必然存在四点共圆。递归去做即可,复杂度线性对数。
半平面交#
随机增量法#
反演变换#
CF1628F
CF1726H
CF755D(V-E+F=2)
SPOJ8073(圆的面积并,辛普森积分)
SCOI2003 切割多边形(直线求交)
SHOI2012 信用卡凸包(凸包)
SCOI2007 最大土地面积(旋转卡壳)
HNOI2007 最小矩形覆盖(旋转卡壳)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构