【计算几何】【凸包】【判断多边形交】Buaacoding1082 AlvinZH的学霸养成记VI

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<cstdio>
#include<complex>
#include<algorithm>
#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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值