Are You Safe? Gym - 102219H 凸包问题
题意:给你n个坐标点,围成一个多边形,之后给你m个坐标点,逆时针输出点,询问你该点是否在凸包内(不包含点和边上)。
思路:计算几何,运用Graham逆时针排序输出,然后判断该点是否在内就行。
#include <iostream> #include <string.h> #include <string> #include <math.h> #include <stdlib.h> #include <vector> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> using namespace std; #define ll long long #define N 100005 #define eps 0.00000001//偏差值1e8 #define pi acos(-1.0)//高精度圆周率 #define fori for(i=0;i<n;i++) #define fori1 for(i=1;i<=n;i++) const int maxp = 1010; //点的数量 int sgn(double x){ //判断x是否等于0 if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; } //定义点及其基本运算 struct Point { double x, y; Point() {} Point(double x, double y) :x(x), y(y) {} Point operator + (Point B) { return Point(x + B.x, y + B.y); } Point operator - (Point B) { return Point(x - B.x, y - B.y); } bool operator ==(Point B) { return sgn(x - B.x) == 0 && sgn(y - B.y) == 0; } bool operator <(Point B) //比较两个点,用于凸包计算 { return sgn(x - B.x) < 0 || (sgn(x - B.x) == 0 && sgn(y - B.y) < 0); } }; Point s[10005],g[10005],h[10005]; typedef Point Vector; //定义向量 double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; } //点积 double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; } //叉积 struct Line { //线上的两个点 Point p1, p2; Line(){} Line(Point p1,Point p2):p1(p1),p2(p2){} Line(Point p, double angle) { p1 = p; if (sgn(angle - pi / 2) == 0) { p2 = (p1 + Point(0, 1)); } else { p2 = (p1 + Point(1, tan(angle))); } } }; double mult(Point a, Point b, Point o) { /////计算叉乘 ao 和 bo return (a.x - o.x) * (b.y - o.y) >= (b.x - o.x) * (a.y - o.y); } int Graham(Point p[], int n, Point res[]) { //逆时针排序,构造凸包形状 int top = 1; sort(p, p + n); if (n == 0) return 0; res[0] = p[0]; if (n == 1) return 0; res[1] = p[1]; if (n == 2) return 0; res[2] = p[2]; for (int i = 2; i < n; i++) { while (top && (mult(p[i], res[top], res[top - 1]))) top--; res[++top] = p[i]; } int len = top; res[++top] = p[n - 2]; for (int i = n - 3; i >= 0; i--) { while (top != len && (mult(p[i], res[top], res[top - 1]))) top--; res[++top] = p[i]; } return top; } struct Polygon { int n; //多边形的顶点数 Point p[maxp]; //多边形的点 Line v[maxp]; //多边形的边 }; //点和线段的关系:0为点p不在线段v上;1为点p在线段v上 bool Point_on_seg(Point p, Line v) { return sgn(Cross(p - v.p1, v.p2 - v.p1)) == 0 && sgn(Dot(p - v.p1, p - v.p2)) <= 0; } //判断点和任意多边形的关系:3为点上;2为边上;1为内部;0为外部 int Point_in_polygon(Point pt, Point* p, int n) { int i; for (i = 0; i < n; i++) { if (p[i] == pt)return 3; } for (i = 0; i < n; i++) { Line v = Line(p[i],p[(i + 1) % n]); if (Point_on_seg(pt, v))return 2; } int num = 0; for (int i = 0; i < n; i++) { int j = (i + 1)%n; int c = sgn(Cross(pt - p[j], p[i] - p[j])); int u = sgn(p[i].y - pt.y); int v = sgn(p[j].y - pt.y); if (c > 0 && u < 0 && v >= 0)num++; if (c < 0 && u >= 0 && v < 0)num--; } return num != 0; } int main() { ll book[10005]; ll i, j, k; ll n,t,m; ll sum = 0, ret = 0,ret2=0; ll ans = 0; ll flag = 1; ll d; cin >> t; while (t--) { cin >> n >> m; fori cin >> s[i].x >> s[i].y; n = Graham(s, n, h); //cout << n << endl; for (i = 0; i < m; i++) cin >> g[i].x >> g[i].y; if (ret) cout << endl; cout << "Case " << ++ret << endl; fori printf("%.0lf %.0lf\n", h[i].x, h[i].y); printf("%.0lf %.0lf\n", h[0].x, h[0].y); for (i = 0; i < m; i++) { if (!Point_in_polygon(g[i], h, n))//在外部 cout << g[i].x << " " << g[i].y << " is safe!" << endl; else//在内部 cout << g[i].x << " " << g[i].y << " is unsafe!" << endl; } } }