1. 程式人生 > >1016 - 計算幾何之直線與線段的交 - Segments(POJ 3304)

1016 - 計算幾何之直線與線段的交 - Segments(POJ 3304)

傳送門

 

題意

雖然題目是給了什麼投影啊,什麼奇奇怪怪的東西

但實際上也就是給你 n 條線段,詢問是否存在一條直線能經過所有的線段

資料範圍:n<=100

 

分析

這個資料範圍有點友好啊……

我們先來想一個問題

若存在一條直線使其能穿過所有的線段,那我們一定可以將這條線段進行一定角度的旋轉,然後使其恰好被卡在某兩條線段的端點之間

也就是說若我們能夠找到被某兩個線段端點卡住的直線,使其穿過所有的線段,則一定存在一組合法解

根據逆反定理,若我們找不到這樣的直線,則原題一定不存在合法解

由於資料範圍很友好,我們就直接暴力列舉(n^3)

 

程式碼

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define eps 1e-8
#define N 105
using namespace std;
int T,n;
struct Point{
	double x,y;
	Point(){}
	Point(double _x,double _y):x(_x),y(_y){}
	friend inline Point operator +(const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y);
	}
	friend inline Point operator -(const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
	friend inline Point operator *(double k,const Point &a){
		return Point(k*a.x,k*a.y);
	}
	friend inline double dot(const Point &a,const Point &b){
		return (a.x*b.x+a.y*b.y);
	}
	friend inline double cross(const Point &a,const Point &b){
		return (a.x*b.y-b.x*a.y);
	}
	friend inline double len(const Point &a){
		return sqrt(dot(a,a));
	}
	friend inline double dis (const Point &a,const Point &b){
		return len(a-b);
	}//向量常見的運算 
};
struct Line{
	Point a,b;
}line[N];
bool check(Point x,Point y){
	if(dis(x,y)<eps) return false;//必須要要的
	for(int i=1;i<=n;++i){
		if(cross(x-line[i].a,y-line[i].a)*cross(x-line[i].b,y-line[i].b)>eps) return false; 
	}
	return true;
}
int main(){
	scanf("%d",&T);
	int i,j,k;
	while(T--){
		scanf("%d",&n);
		for(i=1;i<=n;++i)
			scanf("%lf%lf%lf%lf",&line[i].a.x,&line[i].a.y,&line[i].b.x,&line[i].b.y);
		if(n==1){ printf("Yes!\n");continue; } 
		int flag=0;
		for(i=1;i<n;++i)
		{
			for(j=i+1;j<=n;++j){
				if(check(line[i].a,line[j].a)||check(line[i].a,line[j].b)||check(line[i].b,line[j].a)||check(line[i].b,line[j].b)){
					flag=1;
					break;
				}
			}
			if(flag){
				printf("Yes!\n");
				break;
			} 
		}
		if(!flag) printf("No!\n");
	}
	return 0;
}