ACM暑期集训10

今天主要学习力计算几何基础。

以下主要给出计算几何的一些算法的代码,而分析问题,知道所需算法也十分重要。

1.凸包

1)先上凸包需要的数据结构

完善点的数据结构:
struct Point {
	double x, y;
	Point(double x=0, double y=0): x(x), y(y) {}					//构造函数
	Point operator + (Point p) {return Point(x+p.x, y+p.y);}				//两向量相加
	Point operator - (Point p) {return Point(x-p.x, y-p.y);}				//两向量相减
	Point operator * (double k) {return Point(k*x, k*y);}				//向量的数乘
	Point operator / (double k) {return Point(x/k, y/k);}				//向量的数乘(乘以一个分数)
	bool operator < (const Point &p) const {return x!=p.x ? (x Polygon;

2)判断点与向量的位置关系

int ccw(Point p0, Point p1, Point p2) {
	Vector v1 = p1-p0;
	Vector v2 = p2-p0;
	if(v1.cross(v2) > 0) return 1;			//逆时针方向
	if(v1.cross(v2) < 0) return -1;			//顺时针方向
	if(v1.dot(v2) < 0) return 2;			//同一直线上的反方向
	if(v1.norm() < v2.norm()) return -2;	//同一直线上的正方向
	return 0;								//在向量上
}

3)安德鲁算法O(n*log(n))

Polygon convexHull(Polygon source) {
	if(source.size() < 3) return source;	//当点的个数少于三个,直接返回原点集
	Polygon upper, lower;			//凸包的上下部分
	sort(source.begin(), source.end());	//原点集内点的排序
	upper.push_back(source[0]);
	upper.push_back(source[1]);
	lower.push_back(source[source.size()-1]);
	lower.push_back(source[source.size()-2]);
	for(int i=2; i=1 && ccw(upper[n-1], upper[n], source[i])!=-1; --n)
			upper.pop_back();		//当上部出现不合适的点时删除
		upper.push_back(source[i]);
	}
	for(int i=source.size()-3; i>=0; --i) {	//构建凸包下部
		for(int n=lower.size()-1; n>=1 &&ccw(lower[n-1], lower[n], source[i])!=-1; --n)
			lower.pop_back();		//当下部出现不合适的点时删除
		lower.push_back(source[i]);
	}
	for(int i=1; i

2.其他数据结构

线段:
struct Segment {
    Point p1, p2;
};

直线:
typedef Segment Line;

圆:
struct Circle {
    Point o;			//圆心
    double radius;		//半径
}

3.其他算法

1)直线的正交和平行判断

首先求出两条直线对应的向量

两向量的内积为0,则两直线正交(相互垂直)

两向量外积为0,则两直线平行

2)投影

Point project(Segment s, Point p) {
	Vector base = s.p2 - s.p1;
	double r = (p-s.p1).dot(base)/base.norm();
	return s.p1 + base*r;
}

3)映像(关于直线的对称点)

Point reflect(Segment s, Point p) {
	return p + (project(s, p) - p)*2.0;
}

4)距离

两点间距离:略

点与直线的距离:
double getDist(Line l, Point p) {
	return abs((l.p2-l.p1).cross(p-l.p1) / (l.p2-l.p1).abs());
}

点与线段的距离:
double getDist(Segment s, Point p) {
	if((s.p2-s.p1).dot(p-s.p1) < 0) return (p-s.p1).abs();
	if((s.p1-s.p2).dot(p-s.p2) < 0) return (p-s.p2).abs();
	return abs((s.p2-s.p1).cross(p-s.p1) / (s.p2-s.p1).abs());
}

线段之间的距离:

每条线段的两个端点到另一条线段的距离中的最小值

5)判断两线段是否相交

bool intersect(Point p1, Point p2, Point p3, Point p4) {
	return ccw(p1, p2, p3)*ccw(p1, p2, p4)<=0 &&
			ccw(p3, p4, p1)*ccw(p3, p4, p2)<=0;
}

6)求两线段的交点

Point getCrossPoint(Segment s1, Segment s2) {
	Vector base = s2.p2 - s2.p1;
	double d1 = abs(base.cross(s1.p1-s2.p1));
	double d2 = abs(base.cross(s1.p2-s2.p1));
	double t = d1/(d1+d2);
	return s1.p1 + (s1.p2 - s1.p1)*t;
}

7)计算凸多边形的面积

double getArea(Polygon polygon) {
	double res = 0;
	for(int i=0; i

8)判断一个点是否在多边形内部

int contains(Polygon g, Point p) {
	int n = g.size();
	bool flag = false;
	for(int i=0; i b.y) swap(a, b);
		if(a.y<0 && b.y>0 && a.cross(b)>0) flag = !flag;
	}
	return flag ? 2 : 0;								//2表示在“内”,0表示在“外”
}

9)

 

你可能感兴趣的:(【18暑期集训】)