题意:给定一些点,看能否确定唯一的一个凸包。
题解:只有保证凸包上的每条边都至少有三个点时,才能确定其唯一性。否则可以通过在两点构成的边的外围,增加点的来改变凸包。当所有点都在同一条直线上,或者给定的点少于6个时,不能唯一确定凸包。
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using std::memset;
using std::min;
#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)
struct Point { double x, y; };
Point p[2000], p1, p2;
//计算cross product (P1-P0)x(P2-P0)
double xmult(Point p1,Point p2,Point p0)
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int dots_inline(Point p1,Point p2,Point p3){
return zero(xmult(p1,p2,p3));
}
// graham算法顺时针构造所有共线点的凸包(n*logn)
int graham_cp ( const void* a, const void* b )
{
double ret = xmult(*((Point*)a), *((Point*)b), p1);
if ( ! zero(ret) )
return ret > 0 ? 1 : -1;
return xmult(*(Point*)a, *(Point*)b, p2) > 0 ? 1 : -1;
}
void _graham ( int n, Point* p, int &top, Point* stk )
{
int k = 0, i;
p1 = p2 = p[0];
for ( int i = 1; i < n; i++ ) //找到最左下角的点p1; p2用来求平均值点
{
if ( p1.y - p[i].y > eps || (zero(p1.y-p[i].y) && p1.x > p[i].x) )
p1 = p[k=i];
p2.x += p[i].x; p2.y += p[i].y;
}
p2.x /= n; p2.y /= n;
p[k] = p[0]; p[0] = p1; //将最左下角的点p1与p[0]交换
qsort(p+1,n-1,sizeof(Point),graham_cp);
stk[0] = p[0], stk[1] = p[1], stk[2] = p[2];
for ( top = i = 3; i < n; i++ )
{
while ( top > 2 && xmult(stk[top-2], p[i], stk[top-1] ) < -eps) top--;
stk[top++] = p[i];
}
}
int graham ( int n, Point* p, Point* convex, int maxsize = 1, int dir = 1 )
{
Point *temp = new Point[n];
int s, i;
_graham(n,p,s,temp);
convex[0] = temp[0], n = 1;
for ( i = (dir ? 1:(s-1)); dir ? (i<s) : i; i += (dir ? 1 : -1))
{
if ( maxsize || ! zero(xmult(temp[i-1], temp[i], temp[(i+1)%s])) )
convex[n++] = temp[i];
}
delete [] temp;
return n;
}
int main()
{
int t, n;
Point convex[2000];
scanf("%d",&t);
while ( t-- )
{
scanf("%d",&n);
for ( int i = 0; i < n; i++ )
scanf("%lf %lf",&p[i].x, &p[i].y);
if ( n < 6 ) { printf("NO\n"); continue; }
int tn = graham(n, p, convex, 1, 1);
convex[tn] = convex[0];
bool flag = true;
bool turn = false;
int que[1000];
int front = 0, rear = 0;
que[rear++] = 0; que[rear++] = 1;
for ( int i = 2; i <= tn; i++ )
{
if ( dots_inline(convex[i],convex[que[front]], convex[que[front+1]]) )
que[rear++] = i;
else
{
if ( rear - front < 3 ) { flag = false; break; }
front = rear - 1;
que[rear++] = i;
turn = true;
}
}
if ( flag && turn ) printf("YES\n");
else printf("NO\n");
}
return 0;
}