UVa 10256(凸包、线段交、点在多边形内)

要点

  • 红蓝点分别求凸包显然
  • 判断两凸包是否相交方法:所有红点不在蓝凸包内,反之亦然;所有红凸包线不与蓝凸包线相交,反之亦然。
  • 书上让特判一下凸包退化成点或线段的情况,为什么我感觉代码仓库的代码并没特判并且线段交和点在线段上写的是不包含端点的???
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

typedef double db;
const db PI = acos(-1);
const db eps = 1e-9;
const int maxn = 505;

int dcmp(db x) {
	if (fabs(x) < eps)	return 0;
	return x > 0 ? 1 : -1;
}

struct Point {
	db x, y;
	Point(){}
	Point(db a, db b):x(a), y(b){}
	bool operator < (const Point &rhs) const {
		if (dcmp(x - rhs.x) != 0)	return dcmp(x - rhs.x) < 0;
		return dcmp(y - rhs.y) < 0;
	}
};
typedef Point Vector;

Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Vector A, Vector B) { return Vector(A.x - B.x, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x * p, A.y * p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y / p); }
bool operator == (const Vector& A, const Vector& B) { return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; }

db Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; }//点积

db Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }//叉积

bool isPointOnSegment(Point P, Point A, Point B) { return dcmp(Cross(A - P, B - P)) == 0 && dcmp(Dot(A - P, B - P)) <= 0; }//点在线段上(包含端点,把<=改为<即为不包含端点)

bool Segment_Proper_Intersection(Point a1, Point a2, Point b1, Point b2) {//线段a1a2与b1b2相交(包含端点)
	db c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
	db c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
	if (isPointOnSegment(a1, b1, b2) || isPointOnSegment(a2, b1, b2))//某点在另一条线段上
		return 1;
	if (isPointOnSegment(b1, a1, a2) || isPointOnSegment(b2, a1, a2))
		return 1;
	return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4) < 0;
}

int isPointInPolygon(Point p, Vector *poly, int poly_size) {
	if (poly_size == 1)	return p == poly[0];//多边形退化成点的特判
	
	int wn = 0;
	int n = poly_size;
	for (int i = 0; i < n; i++) {
		if (isPointOnSegment(p, poly[i], poly[(i + 1) % n]))	return -1;//在边界上
		int k = dcmp(Cross(poly[(i + 1) % n] - poly[i], p - poly[i]));
		int d1 = dcmp(poly[i].y - p.y);
		int d2 = dcmp(poly[(i + 1) % n].y - p.y);
		if (k > 0 && d1 <= 0 && d2 > 0)	wn++;
		if (k < 0 && d2 <= 0 && d1 > 0)	wn--;
	}
	if (wn != 0)	return 1;//内部
	return 0;//外部
}

void ConvexHull(Point *p, int n, Point *v, int &cnt) {
	cnt = 0;
	sort(p, p + n);
	n = unique(p, p + n) - p;//去重

	for (int i = 0; i < n; i++) {
		while (cnt > 1 && dcmp(Cross(v[cnt - 1] - v[cnt - 2], p[i] - v[cnt - 2])) <= 0)	cnt--;
		v[cnt++] = p[i];
	}
	int k = cnt;
	for (int i = n - 2; ~i; --i) {
		while (cnt > k && dcmp(Cross(v[cnt - 1] - v[cnt - 2], p[i] - v[cnt - 2])) <= 0)	cnt--;
		v[cnt++] = p[i];
	}
	if (n > 1)	cnt--;
}

int n, m, Acnt, Bcnt;
Point A[maxn], B[maxn], Av[maxn], Bv[maxn];

int main() {
	while (~scanf("%d %d", &n, &m) && (n | m)) {
		for (int i = 0; i < n; i++)
			scanf("%lf %lf", &A[i].x, &A[i].y);
		for (int i = 0; i < m; i++)
			scanf("%lf %lf", &B[i].x, &B[i].y);

		ConvexHull(A, n, Av, Acnt);
		ConvexHull(B, m, Bv, Bcnt);

		bool flag = 0;
		for (int i = 0; i < n; i++)
			if (isPointInPolygon(A[i], Bv, Bcnt) != 0) {
				flag = 1; break;
			}
		for (int i = 0; i < m; i++)
			if (isPointInPolygon(B[i], Av, Acnt) != 0) {
				flag = 1; break;
			}
		if (flag)	goto here;
		for (int i = 0; i < Acnt; i++) {
			Point a1 = Av[i], a2 = Av[(i + 1) % Acnt];
			for (int j = 0; j < Bcnt; j++) {
				Point b1 = Bv[j], b2 = Bv[(j + 1) % Bcnt];
				if (Segment_Proper_Intersection(a1, a2, b1, b2)) {
					flag = 1; break;
				}
			}
			if (flag)	break;
		}
		here:
		printf("%s
", flag ? "No" : "Yes");
	}
}
原文地址:https://www.cnblogs.com/AlphaWA/p/10964239.html