1. 程式人生 > >【計算幾何】Buaacoding1082 AlvinZH的學霸養成記VI

【計算幾何】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