Being the only living descendant of his grandfather, Kamran the Believer inherited all of the grandpa's belongings. The most valuable one was a piece of convex polygon shaped farm in the grandpa's birth village. The farm was originally separated from the neighboring farms by a thick rope hooked to some spikes (big nails) placed on the boundary of the polygon. But, when Kamran went to visit his farm, he noticed that the rope and some spikes are missing. Your task is to write a program to help Kamran decide whether the boundary of his farm can be exactly determined only by the remaining spikes.
Input
The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains an integer n (1 <= n <= 1000) which is the number of remaining spikes. Next, there are n lines, one line per spike, each containing a pair of integers which are x and y coordinates of the spike.
Output
There should be one output line per test case containing YES or NO depending on whether the boundary of the farm can be uniquely determined from the input.
Sample Input
1
6
0 0
1 2
3 4
2 0
2 4
5 0
Sample Output
NO
题意:给你一个凸多变形,判断它是否稳定的凸包
稳定凸包:
比如有4个点:
这四个点是某个凸包上的部分点,他们连起来后确实还是一个凸包。
但是原始的凸包可能不是这样。比如:
即这四个点构成的凸包不算做“稳定”的。我们发现,当凸包上存在一条边上的点只有端点两个点的时候,这个凸包不是稳定的,因为它可以在这条边外再引入一个点,构成一个新的凸包。但一旦一条边上存在三个点,那么不可能再找到一个点使它扩展成一个新的凸包,否则构成的新多边形将是凹的。
下面是一个典型的稳定凸包:
判断是否稳定凸包的方法:
求出给定这堆点的新的凸包,然后判断凸包上的每条边上是否至少有3个点存在,假如有一条边不符合条件,那么就不是稳定凸包。
(关于稳定凸包的解释转自https://www.jianshu.com/p/1d056ac1c881)
题解:就是判断该凸变形的每一条边上是否含有三个以上所给出的点
给一组简单样例:
1
9
0 0
2 0
4 0
4 2
4 4
1 1
2 2
2 1
3 2
YES
附上AC代码:
//#include"bits/stdc++.h"
//#include<unordered_map>
//#include<unordered_set>
#include<iostream>
//#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a,b) memset(a,b,sizeof(a))
#define lson l, mid, node<<1
#define rson mid + 1, r, node<<1|1
const int INF = 0x3f3f3f3f;
const int O = 1e6;
const int mod = 10007;
const int maxn = 2e3 + 5;
const double PI = acos(-1.0);
const double E = 2.718281828459;
const double esp = 1e-7;
struct Point { double x, y; };
// 向量基本模板
typedef Point Vector;
//Vector operator + (Vector a, Vector b) { return { a.x + b.x, a.y + b.y }; }
Vector operator - (Vector a, Vector b) { return { a.x - b.x, a.y - b.y }; }
//Vector operator * (Vector a, double p) { return { a.x * p, a.y * p}; }
//Vector operator / (Vector a, double p) { return { a.x / p, a.y / p}; }
//
//bool operator < (Vector a, Vector b) { return a.x * a.x + a.y * a.y < b.x * b.x + b.y * b.y; }
//bool operator == (Vector a, Vector b) { return fabs(a.x - b.x) < esp && fabs(a.y - b.y) < esp; }
// 点积,模长,角度,叉积,三角形面积,逆时针旋转
//double Dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
//double Length(Vector a) { return sqrt( Dot(a, a) ); }
//double Angle(Vector a, Vector b) { return acos(Dot(a, b) / Length(a) / Length(b)); }
double Cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; } // 大于0时,b在a的逆时针方向
double Area(Point A, Point B, Point C) { return Cross(B - A, C - A) / 2; } // 三角形面积叉乘公式
//Vector Rotate (Vector a, double rad) { return { a.x*cos(rad) - a.y*sin(rad), a.x*sin(rad) + a.y*cos(rad) }; }
//int dcmp(double x) { if(fabs(x) < esp) return 0; else return x < 0 ? -1 : 1; } // 精准判断正负号
// 凸包模板
bool com(Point A, Point B){ return (fabs(A.x - B.x) < esp && A.y < B.y) || A.x < B.x; }
int ConvexHull(Point *P, int n, Point *A){ // P为点集合, A为凸包点(包括边上的点)
sort(P, P + n, com);
int m = 0;
for(int i=0; i<n; i++) {
while(m > 1 && Cross(A[m-1] - A[m-2], P[i] - A[m-2]) < 0) m --;
A[m++] = P[i];
}
int k = m;
for(int i=n-2; i>=0; i--){
while(m > k && Cross(A[m-1] - A[m-2], P[i] - A[m-2]) < 0) m --;
A[m++] = P[i];
}
if(n > 1) m -- ;
return m;
}
int main(){
int T; scanf("%d", &T);
while( T --) {
int n; scanf("%d", &n);
Point P[maxn]; for(int i=0; i<n; i++) scanf("%lf%lf", &P[i].x, &P[i].y);
Point A[maxn]; int k = ConvexHull(P, n, A); // A 为凸包点
bool flag = true;
for(int i=0; i<k; i++) {
Point p1 = A[(i+k-1) % k];
Point p2 = A[i];
Point p3 = A[(i+k+1) % k];
Point p4 = A[(i+k+2) % k];
if(Area(p1, p2, p3) != 0) // 判断p2是否顶点
if(Area(p2, p3, p4) != 0) flag = false; // 如果p2是顶点判断p2,p3,p4是否共线
}
if(k < 6) flag = false; // 形成稳定凸包至少存在6个点
printf(flag ? "YES\n":"NO\n");
}
return 0;
}