AlvinZH的学霸养成记VI
时间限制: 1000 ms 内存限制: 65536 kb
总通过人数: 11 总提交人数: 22
题目描述
AlvinZH已经不想成为一个学霸了!因为在北境的生活还是不错的,除了冷的不行以及异鬼威胁以外。
一天Jon Snow交给他一个艰巨的任务。任务是这样的,“绿先知”布兰·斯塔克“看”到了异鬼大军正在向长城外的各个部落进军,然而各个部落的撤退工作还未完成,可以延缓异鬼军团行军的方法只有一个——龙息!
AlvinZH将要成为一名伟大的龙骑士!龙母慷慨地派出黑龙卓耿与AlvinZH同行,AlvinZH将和黑龙一起去一趟长城以北,为使所有的部落有撤退的时间,AlvinZH与黑龙必须在部落和异鬼大军之间留下龙息,隔离双方。
由于情况紧急,Jon Snow告诉AlvinZH:必须在部落与异鬼大军之间留下一道直线龙息,将部落和异鬼完全分离开来。请问AlvinZH能否完成任务?
输入
输入包含多组数据。
每组数据第一行为正整数n,m,分别代表部落数和异鬼军团数(1≤ n,m ≤ 10^4)。
接下来n行,每行为一个整数坐标对 (x,y),代表部落坐标位置(-10^4≤ x ≤10^4,1≤ y ≤10^4),保证坐标不重复。
接下来m行,每行为一个整数坐标对 (x,y),代表异鬼军团坐标位置(-10^4≤ x ≤10^4,1≤ y ≤10^4),保证坐标不重复。
输出
对于每组数据,输出一行,判断AlvinZH是否能完成任务(“YES” or “NO”)。
输入样例
3 3
1 1
0 1
-1 1
1 2
0 2
-1 2
输出样例
YES
输入样例
2 2
1 1
2 2
1 2
2 1
输出样例
NO
HINT
凸包问题,以及多边形相交的判定问题:先判断点,再判断线段。
从今天开始,每天至少发布一篇题解。毕竟题目做多了,很多都容易忘掉,记一下,锻炼自己和造福他人,岂不美哉。现在基本掌握markdown了,写题解也比较顺手了。
这道题题意很简单,给出两个点集合,问是否存在一条直线能够将其划分。首先用凸包把两个点集合给包起来,显然,如果凸包无交,则直线存在,否则由于直线必须在两个凸包外,所以凸包有交,直线不存在。
多边形是否有交,可以先判断任意两边是否相交,相交则有交。然后取其中一个的某个点,看是否在另一个的内部,如果一内一外,则是包含关系,两外是分离关系。这么做效率最差是n^2的,但是能过。Hint中提到先判断点的方法,我暂时还没有想到。
另外注意,判断线段相交,单用叉积是不够的,因为可能在端点相交,必须要判断一个点是否在另一条线段上或者两点重合。
模板用的基本是刘汝佳的,坐标和向量我用了complex类,效率确实会慢一些,但是代码短了。
#include
#include
#include
#define x real()
#define y imag()
using namespace std;
using db=double;
using Point=complex<db>;
using Vector=Point;
int n,m,an,bn;
Point a[10005],b[10005],ha[10005],hb[10005];
bool cmp(Point &p, Point &q)
{
return p.x<q.x||p.x==q.x&&p.y<q.y;
}
db Cross(Vector A, Vector B)
{
return (conj(A)*B).y;
}
db Dot(Vector A, Vector B)
{
return (conj(A)*B).x;
}
bool OnSegment(Point p, Point a1, Point a2)
{
return Cross(a1-p,a2-p)==0&&Dot(a1-p,a2-p)<0;
}
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2)
{
db c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
return c1*c2<0&&c3*c4<0||OnSegment(a1,b1,b2)
||OnSegment(a2,b1,b2)||OnSegment(b1,a1,a2)||OnSegment(b2,a1,a2)
||a1==b1||a1==b2||a2==b1||a2==b2;
}
int ConvexHull(Point *p, int n, Point * ch)
{
sort(p,p+n,cmp);
int m=0;
for(int i=0;i<n;i++)
{
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-2;i>=0;i--)
{
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
m--;
ch[m++]=p[i];
}
if(n>1)
m--;
return m;
}
bool isPointInPolygon(Point p, Point *poly, int n)
{
int wn=0;
db k,d1,d2;
for(int i=0;i<n;i++)
{
k=Cross(poly[(i+1)%n]-poly[i],p-poly[i]);
d1=poly[i].y-p.y;
d2=poly[(i+1)%n].y-p.y;
if(k>0&&d1<=0&&d2>0)
wn++;
if(k<0&&d2<=0&&d1>0)
wn--;
}
return wn!=0;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
db tx,ty;
for(int i=1;i<=n;i++)
scanf("%lf%lf",&tx,&ty),a[i]=(Point){tx,ty};
for(int i=1;i<=m;i++)
scanf("%lf%lf",&tx,&ty),b[i]=(Point){tx,ty};
an=ConvexHull(a+1,n,ha);
bn=ConvexHull(b+1,m,hb);
bool f=false;
for(int i=0;i<an&&!f;i++)
for(int j=0;j<bn&&!f;j++)
f|=SegmentProperIntersection(ha[i],ha[(i+1)%an],hb[j],hb[(j+1)%bn]);
f|=isPointInPolygon(ha[0],hb,bn)||isPointInPolygon(hb[0],ha,an);
puts(f?"NO":"YES");
}
return 0;
}
吐槽一下csdn的代码高亮是真的丑啊hh