1 条题解
-
0
说明
该代码解决的问题是:给定一组平面上的点(钉子),判断这些点是否能够唯一确定一个凸多边形的边界。换句话说,判断这些点是否恰好构成一个凸多边形的顶点,且没有其他点位于凸多边形的边上。
算法标签
- 计算几何
- 凸包算法
- 点与线段关系
解题思路
- 输入处理:读取测试用例的数量
t
,然后逐个处理每个测试用例。每个测试用例包含点的数量n
和每个点的坐标。 - 计算凸包:使用 Andrew's monotone chain 算法计算给定点集的凸包,得到凸包的顶点序列
ch
和顶点数量m
。 - 特殊情况处理:如果凸包的顶点数量
m
为1或2(即点集退化为点或线段),则直接输出 "NO",因为这些情况无法唯一确定一个凸多边形。 - 检查点是否在凸包边上:对于凸包的每条边,检查是否有点(非顶点)位于该边上。如果有,则说明无法唯一确定凸多边形边界,输出 "NO";否则输出 "YES"。
分析
- 凸包计算:使用 Andrew's monotone chain 算法高效计算凸包,时间复杂度为
O(n log n)
。 - 点与线段关系:通过叉积和点积判断点是否在线段上(不包含端点),确保严格位于线段内部。
- 唯一性判断:只有当所有点要么是凸包的顶点,要么严格位于凸包内部时,才能唯一确定凸多边形边界。如果有任何点位于凸包的边上(非顶点),则无法唯一确定边界。
实现步骤
- 读取输入:读取测试用例的数量
t
,然后逐个处理每个测试用例。 - 计算凸包:对输入的点集进行排序,然后计算凸包的顶点序列
ch
和顶点数量m
。 - 特殊情况处理:如果
m
为1或2,直接输出 "NO"。 - 检查边上的点:对于凸包的每条边,检查是否有点(非顶点)位于该边上。如果有,输出 "NO";否则输出 "YES"。
代码
#include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <cstdio> using namespace std; typedef unsigned long long ll; #define maxn 1111 #define pi acos (-1) #define rotate Rotate const double eps = 1e-8; int dcmp (double x) { if (fabs (x) < eps) return 0; else return x < 0 ? -1 : 1; } struct point { double x, y; point (double _x = 0, double _y = 0) : x(_x), y(_y) {} point operator - (point a) const { return point (x-a.x, y-a.y); } point operator + (point a) const { return point (x+a.x, y+a.y); } bool operator < (const point &a) const { return x < a.x || (x == a.x && y < a.y); } bool operator == (const point &a) const { return dcmp (x-a.x) == 0 && dcmp (y-a.y) == 0; } }; point operator * (point a, double p) { return point (a.x*p, a.y*p); } double cross (point a, point b) { return a.x*b.y-a.y*b.x; } double dot (point a, point b) { return a.x*b.x + a.y*b.y; } int n, m, tot; point p[maxn], ch[maxn]; int ConvexHull () { sort (p, p+n); int m = 0; for (int i = 0; i < n; i++) { while (m > 1 && cross (ch[m-1]-ch[m-2], p[i]-ch[m-1]) <= 0) m--; ch[m++] = p[i]; } int k = m; for (int i = n-2; i >= 0; i--) { while (m > k && cross (ch[m-1]-ch[m-2], p[i]-ch[m-1]) <= 0) m--; ch[m++] = p[i]; } if (n > 1) m--; return m; } bool PointOnSegment (point p, point a1, point a2) { //点在线段上(不包含端点) return dcmp (cross (a1-p, a2-p)) == 0 && dcmp (dot (a1-p, a2-p)) < 0; } void solve () { if (m == 1 || m == 2) { printf ("NO\n"); return ; } bool vis[maxn]; memset (vis, 0, sizeof vis); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (PointOnSegment (p[j], ch[i], ch[(i+1)%m])) vis[i] = 1; } } for (int i = 0; i < m; i++) { if (!vis[i]) { printf ("NO\n"); return ; } } printf ("YES\n"); return ; } int main () { //freopen ("in", "r", stdin); int t; cin >> t; while (t--) { cin >> n; for (int i = 0; i < n; i++) { cin >> p[i].x >> p[i].y; } m = ConvexHull (); solve (); } return 0; }
- 1
信息
- ID
- 229
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者