1. 程式人生 > >SPOJ - TBGAME - 凸包+計算幾何

SPOJ - TBGAME - 凸包+計算幾何

題目連結:https://vjudge.net/problem/SPOJ-TBGAME

 

解題思路:

1.兩線段不想交時肯定有解,理解為將一條線段作為分界線,各自在自己的部分走肯定不會相交.

2.兩線段相交時,如果有解,一定存在一條線段的開始點到終點可以把其他點都遍歷,然後另一個開始點直接連到終點.

這兩條路徑不會相交.

假設另一個開始點直接連終點形成線段l,以l做分界線,s在一頭,t在另外一頭,s可以先把直接在的那一頭的所有點遍歷,之後就是想辦法能不能從直接的這一頭的一個點過度到另一頭的一個點而不經過線段l,如果有,又可以把另一頭的所有點遍歷之後最後返回t點,所以如果s可以不經過l到達t,那麼同時它也可以遍歷完所有的點.

那麼做法是留l線段的兩個點,剩下的n-2個點做凸包,如果線段l不完全將凸包分開那麼就有解.(完全分開是指從線段一頭出發回穿過凸包到達另一頭),因為沒有穿過,所以肯定存在凸包上的一條邊可以不予l相交,而且兩頭分別處於l分界的不同部分。

選兩對點中一對做l,一對做s,t.做兩遍凸包即可,

#include <bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int mod = 1e9;
const int mx = 1e5 + 10;
int n,top;
struct node
{
	double x,y;
}s1,s2,t1,t2,s[mx],w;
node tu[mx],tmp[mx];
int judge(node p1,node p2,node p)
{
	double ans = (p1.x-p.x)*(p2.y-p.y) - (p2.x-p.x)*(p1.y-p.y);
	if(ans==0) return 0;
	if(ans>0) return 1;
	return -1;
}
bool cmp(node a,node b)
{
	int c = judge(w,b,a);
	if(c==0) return pow(a.x-w.x,2)+pow(a.y-w.y,2) < pow(b.x-w.x,2)+pow(b.y-w.y,2);
	return c < 0;
}
int Graham(int len)
{
	int top = 0;
	for(int i=0;i<len;i++){
		while(top>1&&judge(tu[top-2],s[i],tu[top-1])>=0) top--;
		tu[top++] = s[i];
	}
	return top;
}
bool check(node a,node b,node c,node d)
{
	if(judge(a,b,c)*judge(a,b,d)>0) return 0;
	if(judge(c,d,a)*judge(c,d,b)>0) return 0;
	return 1;
}
bool add(node a,node b,node c,node d)
{
	int len = n+2,p = 0;
	for(int i=0;i<n;i++) s[i] = tmp[i];
	s[n] = a,s[n+1] = b;
	for(int i=0;i<len;i++){
		if(s[i].y<s[p].y) p = i;
		else if(s[i].y==s[p].y&&s[i].x<s[p].y) p = i;
	}
	swap(s[0],s[p]);w = s[0];
	sort(s+1,s+len,cmp);
	len = Graham(len);
	for(int i=0;i<len;i++){
		if(!check(tu[i],tu[(i+1)%len],c,d)){
			if(judge(c,d,tu[i])*judge(c,d,tu[(i+1)%len])<0)
			return 1;
		}
	}
	return 0;
} 
int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);n -= 4;
		scanf("%lf%lf",&s1.x,&s1.y);
		scanf("%lf%lf",&t1.x,&t1.y);
		scanf("%lf%lf",&s2.x,&s2.y);
		scanf("%lf%lf",&t2.x,&t2.y);
		for(int i=0;i<n;i++) scanf("%lf%lf",&tmp[i].x,&tmp[i].y);
		if(!check(s1,t1,s2,t2)){
			puts("POSSIBLE");
			continue;
		}
		if(add(s1,t1,s2,t2)||add(s2,t2,s1,t1)) puts("POSSIBLE");
		else puts("IMPOSSIBLE");
	}
	return 0;
}