题目链接:
POJ 1228 Grandpa’s Estate
题意:
给出n个点,问由这n个点能不能位唯一确定一个凸包?
分析:
看到有网友将这称为稳定凸包。
其实就是确定这n个点所形成的凸包每条边上是不是至少有三个点。
当顶点数小于6的时候肯定是不能构成凸包的,这个特判下就好了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cmath>
using namespace std;
const double EPS=1e-10;
const int MAX_N=1010;
const double PI=acos(-1.0);
int n;
struct Point{
double x,y;
Point () {}
Point (double x,double y) : x(x),y(y) {
}
Point operator + (const Point& rhs) const {
return Point(x+rhs.x,y+rhs.y);
}
Point operator - (const Point& rhs) const {
return Point(x-rhs.x,y-rhs.y);
}
Point operator * (const double d) const {
return Point(x*d,y*d);
}
double cross(const Point& rhs) const {
return (x*rhs.y-y*rhs.x);
}
}point[MAX_N],res[MAX_N];
bool cmp_x(Point a,Point b)
{
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
int Andrew()
{
sort(point,point+n,cmp_x);
int k=0;
for(int i=0;i<n;i++){
while(k>1 && (res[k-1]-res[k-2]).cross(point[i]-res[k-1])<=0) k--;
res[k++]=point[i];
}
int m=k;
for(int i=n-2;i>=0;i--){
while(k>m && (res[k-1]-res[k-2]).cross(point[i]-res[k-1])<=0) k--;
res[k++]=point[i];
}
if(k>1) k--;
return k;
}
void solve()
{
int total=Andrew();
//printf("total=%d\n",total);
/*
将边上的点也存进凸包顶点里,在判断的时候只需要判断凸包顶点中是否一定存在相邻向量叉积为0即可
上面Andrew()函数中需要将(res[k-1]-res[k-2]).cross(point[i]-point[k-1])<=0改为
(res[k-1]-res[k-2]).cross(point[i]-point[k-1])
int flag=1;
for(int i=1;i<total;i++){
if((res[i-1]-res[i]).cross(res[(i+1)%total]-res[i])!=0
&&(res[i]-res[(i+1)%total]).cross(res[(i+2)%total]-res[(i+1)%total])!=0){
printf("NO\n");
flag=0;
break;
}
}
if(flag){
printf("YES\n");
}
*/
int flag=1;
for(int i=0;i<total;i++){ //遍历凸包边
Point a=res[i],b=res[(i+1)%total];//该边端点是a和b
int cnt=0;
for(int j=0;j<n;j++){ //检查该边上点的个数
//printf("i=%d j=%d %.2f\n",i,j,fabs((point[j]-a).cross(b-point[j])));
if((point[j]-a).cross(b-point[j])==0){// 在这条边上的点
cnt++;
if(cnt>=3) break;
}
}
if(cnt<3){ //少于三个点
//printf("i=%d\n",i);
printf("NO\n");
flag=0;
break;
}
}
if(flag) printf("YES\n");
}
int main()
{
//freopen("Din.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf%lf",&point[i].x,&point[i].y);
}
//要构成稳定凸包至少需要5个顶点(构成三角形)
if(n<6){
printf("NO\n");
continue;
}
solve();
}
return 0;
}