题目链接
题目大意
按顺序给出一个多边形,问你这个多边形有没有内核;
解题思路
求一个半平面交,如果点的个数是大于等于三个的,就有内核,否则,没有;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int N=1e5+5;
const double eps=1e-5;
struct node
{
double x,y;
node() {}
node(int X,int Y)
{
x=X;
y=Y;
}
node operator - (const node &a)
{
return node(x-a.x,y-a.y);
}
};
node e[N];
struct line
{
node x,y;
line() {}
line(node X,node Y)
{
x=X;
y=Y;
}
};
line l[N],que[N];
int n;
double cross(node a,node b)
{
return a.x*b.y-a.y*b.x;
}
//返回点是不是逆时针顺序
int judge()
{
double ans=0;
for(int i=0; i<n-1; i++)
ans+=(e[i].x*e[i+1].y-e[i+1].x*e[i].y);
return ans>0;
}
//向量极角
double angle(node a)
{
return atan2(a.y,a.x);
}
//直线极角
double angle1(line a)
{
return atan2(a.y.y-a.x.y,a.y.x-a.x.x);
}
//排序:按照极角从小到大,极角相同的最左边的排后面
int cmp(line a,line b)
{
node t1=a.y-a.x;
node t2=b.y-b.x;
double A=angle(t1),B=angle(t2);
if(fabs(A-B)<eps)
return cross(t1,b.y-a.x)>=0.0;
return A<B;
}
//两直线的交点
node getnode(line a,line b)
{
double a1 = a.x.y - a.y.y, b1 = a.y.x - a.x.x, c1 = a.x.x * a.y.y - a.y.x * a.x.y;
double a2 = b.x.y - b.y.y, b2 = b.y.x - b.x.x, c2 = b.x.x * b.y.y - b.y.x * b.x.y;
return node((c1*b2-c2*b1)/(a2*b1-a1*b2), (a2*c1-a1*c2)/(a1*b2-a2*b1));
}
//判断b和c的交点是不是在直线a的右面
int right(line a,line b,line c)
{
node A=getnode(b,c);
if(cross((a.y-a.x),(A-a.x))<0.0)
return 1;
return 0;
}
//半平面交
int half()
{
sort(l,l+n,cmp);
int head=0,tail=0,cnt=0;
for(int i=0; i<n-1; i++)//去重
{
if(fabs(angle1(l[i])-angle1(l[i+1]))<eps)
continue;
l[cnt++]=l[i];
}
l[cnt++]=l[n-1];
//更新新加入的直线产生的影响
for(int i=0; i<cnt; i++)
{
while(head+1<tail&&right(l[i],que[tail-1],que[tail-2]))
tail--;
while(head+1<tail&&right(l[i],que[head],que[head+1]))
head++;
que[tail++]=l[i];
}
//判断最后一个加入的和第一个加入的直线的影响
while(head+1<tail&&right(que[head],que[tail-1],que[tail-2]))
tail--;
while(head+1<tail&&right(que[tail-1],que[head],que[head+1]))
head++;
return (tail-head)>=3;//最后的点大于等于三个则有内核
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lf %lf",&e[i].x,&e[i].y);
if(judge())//按逆时针顺序建边
{
for(int i=n-1; i>=0; i--)
l[i]=line(e[(i+1)%n],e[i]);
}
else
{
for(int i=n-1; i>=0; i--)
l[i]=line(e[i],e[(i+1)%n]);
}
if(half())
printf("YES\n");
else
printf("NO\n");
}
return 0;
}