1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
| //poj3335求多边形有无核
struct Line {
Point s, e;
Line() {}
Line(Point a, Point b) {s = a, e = b;}
};
double getAngle(Line a){
return atan2(a.e.y-a.s.y,a.e.x-a.s.x);
}
bool operator<(Line a,Line b){
double A=getAngle(a);
double B=getAngle(b);
if(fabs(A-B)<eps) return ((a.e-a.s)^(b.e-a.s))>0; //把靠右的排在前面
else return A<B;
}
Point getIntersectPoint(Line a,Line b){ //用线段b的两点坐标组合成交点坐标
double u=a.s.cross(a.e,b.e);
double v=a.e.cross(a.s,b.s);
return Point((v*b.e.x+u*b.s.x)/(u+v),(v*b.e.y+u*b.s.y)/(u+v));
}
bool onRight(Line a,Line b,Line c){ //判断bc交点是否在a的右边
Point o=getIntersectPoint(b,c);
if(((a.e-a.s)^(o-a.s))<0) //这里不能取等,也许是因为能留下一条边就尽量留?这样tail-head的合法判定更易满足
return true;
return false;
}
Line lines[maxn];
Line que[maxn];
Point ps[maxn];
int n;
bool HalfPlaneIntersect(){
sort(lines,lines+n);
int head=0,tail=0,cnt=0;
for(int i=0;i<n-1;i++){
if(fabs(getAngle(lines[i])-getAngle(lines[i+1]))<eps){
continue;
}
lines[cnt++]=lines[i];
}
lines[cnt++]=lines[n-1];
for(int i=0;i<cnt;i++){
while(tail-head>1&&onRight(lines[i],que[tail-1],que[tail-2])) //用新边优化队尾
tail--;
while(tail-head>1&&onRight(lines[i],que[head],que[head+1])) //用新边优化队首
head++;
que[tail++]=lines[i];
}
while(tail-head>1&&onRight(que[head],que[tail-1],que[tail-2]))
tail--;
while(tail-head>1&&onRight(que[tail-1],que[head],que[head+1]))
head++;
if(tail-head<3)
return false;
return true;
}
bool judge() { //判断点的顺序是逆时针
double ans = 0;
for(int i=1; i<n-1; i++) {
ans += ((ps[i]-ps[0])^(ps[i+1]-ps[0]));
}
return ans>0;
}
int t;
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=0;i<n;i++)
cin>>ps[i].x>>ps[i].y;
if(judge()){
for(int i=0;i<n;i++)
lines[i]=Line(ps[i],ps[(i+1)%n]);
}else{
for(int i=0;i<n;i++){
lines[i]=Line(ps[(i+1)%n],ps[i]);
}
}
if(HalfPlaneIntersect()){
printf("YES\n");
}else
printf("NO\n");
}
return 0;
}
|