(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
目录
题意:传送门
题目描述
Z市是一座港口城市,来来往往的船只依靠灯塔指引方向。
在海平面上,存在n个灯塔。每个灯塔可以照亮以它的中心点为中心的90°范围。特別地, 由于特殊限制,每个灯塔照亮范围的角的两条边必须要么与坐标轴平行要么与坐标轴成45°。 由于经费限制,Z市的灯塔只能被点亮一座。你需要求出在这种情况下,是否存在一座灯塔能够照亮Z市的所有灯塔。
输入描述:
第一行一个整数T,表示数据组数。
对于每组数据,第一行一个整数n,表示灯塔的数量。
接下来n行,每行两个整数xi,yi,表示第i座灯塔的坐标点。
输出描述:
如果存在一座灯塔能够照亮Z市的所有灯塔则输出Yes,否则输出No(区分大小写)。
思路:
首先选取最上面最下面最左边最右边的四个点。
然后枚举这四个点,算出其他所有点到这一个点的角度,然后排序。
排完序之后看这点角度符不符合题目所说的要求。要么全在一个象限内,要么在
y
=
x
y=x
y=x和
y
=
−
x
y=-x
y=−x俩直线之间。
丫的,之前百度了一份凸包模版,然后一直不对,后来删掉凸包部分就过了,恶心
然后在日天学长要了一份凸包模版,这tm才是正确的凸包嘛,用了日天的凸包也过了。凸包模版请看这里:传送门
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MX = 1e6 + 5;
const double pi = acos(-1.0);
struct lp {
LL x, y;
} cw[MX],R[MX],op[5],ok;
bool cmp1(lp &a, lp &b){
return a.x<b.x;
}
bool cmp2(lp &a, lp &b){
return a.y<b.y;
}
double ans[MX];
int main() {
#ifndef ONLINE_JUDGE
freopen("E://ADpan//in.in", "r", stdin);
//freopen("E://ADpan//out.out", "w", stdout);
#endif
int T, n;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%lld%lld",&cw[i].x,&cw[i].y);
}
int flag = 0;
sort(cw,cw+n,cmp2);
op[3]=cw[0],op[4]=cw[n-1];
sort(cw,cw+n,cmp1);
op[1]=cw[0],op[2]=cw[n-1];
double haha = pi/2;
for(int t=1;t<=4;++t){
int tn = 0;
ok=op[t];
int res=1;
for(int i=0;i<n;++i){
if(cw[i].x==ok.x&&cw[i].y==ok.y)continue;
ans[tn++]=atan2(cw[i].y-ok.y*1.0,1.0*cw[i].x-ok.x);
if(ans[tn-1]>-pi*3/4&&ans[tn-1]<pi*3/4)res=0;
}
sort(ans,ans+tn);
double mmax=ans[tn-1],mmin=ans[0];
if(mmax<=-haha)flag=1;
if(mmin>=-3*pi/4&&mmax<=-pi/4)flag=1;
if(mmin>=-haha&&mmax<=0)flag=1;
if(mmin>=-pi/4&&mmax<=pi/4)flag=1;
if(mmin>=0&&mmax<=haha)flag=1;
if(mmin>=pi/4&&mmax<=pi*3/4)flag=1;
if(mmin>=haha&&mmax<=pi)flag=1;
if(res)flag=1;
}
if(flag)printf("Yes\n");
else printf("No\n");
}
return 0;
}