题目地址:http://poj.org/problem?id=1228
凸包丢失了若干个点,给你剩余的点,求这些剩余的点能不能构成一个唯一的凸包,即剩余点加上任意点(剩余点还在凸包边上),只能构成一个凸包。
在剩余点中,一遍至少三个点才能保持唯一性,两点的话可以在两点之间的外面加一点,三点加一点的话,原先三点中的中间的点会失效。
一种错误的写法
建两个凸包,一个允许多点共线,一个不允许,看这两个凸包是否存在边相等,
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAXN=50098;
const double PI=acos(-1.0);
struct point
{
int x,y;
};
point list[MAXN];
int stack1[MAXN],stack2[MAXN],top1,top2;
int cross(point p0,point p1,point p2) //计算叉积 p0p1 X p0p2
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2) //计算 p1p2的 距离
{
return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面
{
int tmp=cross(list[0],p1,p2);
if(tmp>0) return true;
else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
else return false;
}
void init(int n) //输入,并把 最左下方的点放在 list[0] 。并且进行极角排序
{
int i,k;
point p0;
scanf("%d%d",&list[0].x,&list[0].y);
p0.x=list[0].x;
p0.y=list[0].y;
k=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&list[i].x,&list[i].y);
if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
{
p0.x=list[i].x;
p0.y=list[i].y;
k=i;
}
}
list[k]=list[0];
list[0]=p0;
sort(list+1,list+n,cmp);
}
void graham1(int n)
{
int i;
if(n==1) {top1=0;stack1[0]=0;}
if(n==2)
{
top1=1;
stack1[0]=0;
stack1[1]=1;
}
if(n>2)
{
for(i=0;i<=1;i++) stack1[i]=i;
top1=1;
for(i=2;i<n;i++)
{
while(top1>0&&cross(list[stack1[top1-1]],list[stack1[top1]],list[i])<=0) top1--;
top1++;
stack1[top1]=i;
}
}
}
void graham2(int n)
{
int i;
if(n==1) {top2=0;stack2[0]=0;}
if(n==2)
{
top2=1;
stack2[0]=0;
stack2[1]=1;
}
if(n>2)
{
for(i=0;i<=1;i++) stack2[i]=i;
top2=1;
for(i=2;i<n;i++)
{
while(top2>0&&cross(list[stack2[top2-1]],list[stack2[top2]],list[i])<0) top2--;
top2++;
stack2[top2]=i;
}
}
}
bool judge()
{
int j=0;
top1++;
top2++;
for(int i=0;i<top1;i++)
{
while(stack1[i]!=stack2[j])
j=(j+1)%top2;
if(stack1[i]==stack2[j]&&stack1[(i+1)%top1]==stack2[(j+1)%top2])
return false;
}
return true;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(stack1,0,sizeof(stack1));
init(n);
graham1(n);
graham2(n);
if(judge())
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
一种AC的:
建一个允许多点共线的凸包,求他与相邻两点或其后两点是否共线
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
const int MAXN=1005;
const double PI=acos(-1.0);
struct point
{
int x,y;
};
point list[MAXN];
int stack[MAXN],top;
int cross(point p0,point p1,point p2) //计算叉积 p0p1 X p0p2
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2) //计算 p1p2的 距离
{
return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面
{
int tmp=cross(list[0],p1,p2);
if(tmp>0) return true;
else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
else return false;
}
void init(int n) //输入,并把 最左下方的点放在 list[0] 。并且进行极角排序
{
int i,k;
point p0;
scanf("%d%d",&list[0].x,&list[0].y);
p0.x=list[0].x;
p0.y=list[0].y;
k=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&list[i].x,&list[i].y);
if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
{
p0.x=list[i].x;
p0.y=list[i].y;
k=i;
}
}
list[k]=list[0];
list[0]=p0;
sort(list+1,list+n,cmp);
}
void graham(int n)
{
int i;
if(n==1) {top=0;stack[0]=0;}
if(n==2)
{
top=1;
stack[0]=0;
stack[1]=1;
}
if(n>2)
{
for(i=0;i<=1;i++) stack[i]=i;
top=1;
for(i=2;i<n;i++)
{
while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<0) top--;
top++;
stack[top]=i;
}
}
}
bool judge()
{
//stack[++top]=stack[0];
//stack[++top]=stack[1];
//printf("%d\n",top);
/* for(int i=0;i<=top;i++)
{
printf("%d %d *",list[stack[i]].x,list[stack[i]].y);
}
printf("\n");*/
for(int i=0;i<top;i++)
{
if(i==0)
{
if(cross(list[stack[i]],list[stack[i+1]],list[stack[i+2]])!=0)
{
//printf("%d**\n",i);
// printf("%d %d %d %d %d %d\n",
///list[stack[i]].x,list[stack[i]].y,list[stack[i+1]].x,list[stack[i+1]].y,list[stack[i+2]].x,list[stack[i+2]].y);
return false;
}
}
else
if(cross(list[stack[i]],list[stack[i+1]],list[stack[i+2]])!=0&&cross(list[stack[i-1]],list[stack[i]],list[stack[i+1]])!=0)
return false;
}
return true;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(stack,0,sizeof(stack));
init(n);
graham(n);
if(n<6)
{
printf("NO\n");
continue;
}
else
{
if(judge())
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
发现一点数据bug
1
7
0 0
1 0
2 0
2 1
2 2
1 2
0 2
YES
按照题意是NO AC代码确实YES
真正AC的代码
1将凸包求全了
2判断凸包最后两个点的时候改进了
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
const int MAXN=1005;
const double PI=acos(-1.0);
int flag;
struct point
{
int x,y;
};
point list[MAXN];
int stack[MAXN],top;
int cross(point p0,point p1,point p2) //计算叉积 p0p1 X p0p2
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2) //计算 p1p2的 距离
{
return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面
{
int tmp=cross(list[0],p1,p2);
if(tmp>0) return true;
else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
else return false;
}
void init(int n) //输入,并把 最左下方的点放在 list[0] 。并且进行极角排序
{
int i,k;
point p0;
scanf("%d%d",&list[0].x,&list[0].y);
p0.x=list[0].x;
p0.y=list[0].y;
k=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&list[i].x,&list[i].y);
if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
{
p0.x=list[i].x;
p0.y=list[i].y;
k=i;
}
}
list[k]=list[0];
list[0]=p0;
sort(list+1,list+n,cmp);
}
void graham(int n)
{
int i;
if(n==1) {top=0;stack[0]=0;}
if(n==2)
{
top=1;
stack[0]=0;
stack[1]=1;
}
if(n>2)
{
for(i=0;i<=1;i++) stack[i]=i;
top=1;
for(i=2;i<n;i++)
{
while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<0) top--;
top++;
stack[top]=i;
}
}
// printf("&&\n");
for(int i=stack[top]-1;i>0;i--)
{
if(cross(list[0],list[stack[top]],list[i])==0)
{
stack[++top]=i;
}
}
//printf("%d\n",top);
}
bool judge()
{
stack[++top]=stack[0];
stack[++top]=stack[1];
/*printf("%d\n",top);
for(int i=0;i<=top;i++)
{
printf("%d %d *",list[stack[i]].x,list[stack[i]].y);
}
printf("\n");*/
for(int i=0;i<top-1;i++)
{
if(i==0)
{
if(cross(list[stack[i]],list[stack[i+1]],list[stack[i+2]])!=0)
return false;
}
else
if(cross(list[stack[i]],list[stack[i+1]],list[stack[i+2]])!=0&&cross(list[stack[i-1]],list[stack[i]],list[stack[i+1]])!=0)
return false;
}
return true;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(stack,0,sizeof(stack));
init(n);
graham(n);
if(n<6)
{
printf("NO\n");
continue;
}
else
{
if(judge())
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}