Loading

计算几何从入门到入棺

众所周知,国内oi比赛很不喜欢考计算几何题,尤其是一些纯解析几何题,所以平常在这方面的训练会少很多。但是国外比赛和acm比赛又经常很注重这个玩意,故收集一些这里的题。

算法

平面计算几何初步

向量 用一个点 \((x,y)\) 来表示向量 \(\vec{a}=(x,y)\)

向量的模 \(|\vec{a}|=\sqrt{x^2+y^2}\)

向量的加减法 \(\vec{a}+\vec{b}=(x_a+x_b,y_a+y_b),\vec{a}-\vec{b}=(x_a-x_b,y_a-y_b)\)

向量数乘 \(c\vec{a}=(cx,cy)\)

线段长度 \(|AB|=|\vec{a}-\vec{b}|\)

线段上一点 \(C=\sigma A+(1-\sigma)B\)

向量点积 \(\vec{a}\cdot \vec b=x_1x_2+y_1y_2=|a||b|\cos\theta\)

向量叉积 \(\vec a\times \vec b = x_1y_2 - x_2y_1\),如果 \(\vec a\times \vec b>0\) 说明 \(b\)\(a\) 的逆时针方向。

直线 \(Ax+By+C=0\),与 \(x\) 轴夹角的正切值 \(-\dfrac{A}{B}\)

点到直线距离 \(\dfrac{|Ax_0+By_0+c|}{\sqrt{A^2+B^2}}\)

\((x-a)^2+(y-b)^2=r^2\)

向量旋转 \(a'=(x\cos\alpha-y\sin\alpha,x\sin\alpha+y\cos\alpha)\)

正弦定理 \(\dfrac{a}{\sin A}=\dfrac{b}{\sin B}=\dfrac{c}{\sin C}=2R\)

余弦定理 \(c^2=a^2+b^2-2ab\cos\theta\)

判断点是否在线段上 点必须在以线段为对角线的矩形里,然后叉积为 \(0\)

点是否在任意多边形中 引出一条射线交点个数为奇数,随机化

点是否在凸多边形中,任意一条边与其中一个端点到该点的向量的叉积的正负形相同。

线段是否相交 \((B-A)\times (C-A)\)\((B-A)\times (D-A)\) 不同号,且 \((D-C)\times (A-C)\)\((D-C)\times (B-C)\) 不同号。

线段求交 定比分点

一些求交点,垂心的通用做法:算出边长,然后求出正切值从而得到角度,进行向量旋转。

注意,尽量不要用解析法列方程

面积

凸多边形 找一个点然后把凸包分成若干三角形

自适应辛普森法

对二次函数求积分:

\[f(x)=ax^2+bx+c\\ \int_{l}^{r}=\dfrac{4(f(l)+f(r)+f(\dfrac{l+r}{2}))}{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+\dfrac{b}{2}-1\)

换成三角形格点:\(A=2i+b-2\)

euler formula

\(V-E+F=2\),其中 \(V\) 是节点数,\(E\) 是边数 \(F\) 是面数。

看成凸多面体证明显然。

凸包

凸多边形是指所有内角大小都在 \([0,\pi]\) 范围内的 简单多边形。

在平面上能包含所有给定点的最小凸多边形叫做凸包。

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 最小矩形覆盖(旋转卡壳)

posted @ 2023-01-18 18:42  Semsue  阅读(46)  评论(0编辑  收藏  举报
Title