POJ 3304 Segments (叉积的运用---判断线段相交+枚举)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/PK__PK/article/details/83110495

题目链接:http://poj.org/problem?id=3304

题意:给你n条线段,然后问是否存在一条直线,让所有线段在这条直线上的投影至少有一个公共点。

题解:我读题读了10年才读懂QAQ (太菜了)。这道题实际问的是是否存在一条直线与所有线段有交点。

如何从题意,转化到这里呢?

首先投影一定是和直线是垂直的,若所有直线至少有一个公共点,那么过这个公共点作垂线,一定和所有线段有交点。(读不懂画个图,显然的东西)。

然后问题就变成是否存在一条直线与所有线段有交点。再考虑,如何判断这条直线存不存在。

有如下几种情况。

1,没有交点。

2,有一个交点

3,有n个交点

若只存在一个交点,那么就是说这个交点是由线段的端点映射上的。所以我们只需要枚举任意两条线段的端点构成的直线,即是所求直线。然后问题有变成了判断线段相交。

判断线段相交,要理由快速排斥实验和跨立实验。其本质是利用叉积来判断。

以一条线段为标准,来判断另一条线段的端点是否在同一侧。

向量P×向量Q  > 0 ,向量P在Q的顺时针方向

向量P×向量Q  < 0 向量P 在Q的顺时针方向

向量P×向量Q == 0 在同一侧。

然后这道题 还需要判断重复的点 。切记。

#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>

using namespace std;
const double eps = 1e-8;
const int N = 1005,maxn = 100005,inf = 0x3f3f3f3f3f;

struct point{
	double x,y;
}; 
struct line{
	point a,b;
}l[N];

int n;
double mul(point p,point u,point v){
	return (u.x - v.x)*(p.y - u.y) - (u.y - v.y)*(p.x - u.x);
}

bool ok(point u,point v){
	if(fabs(u.x - v.x) < eps && fabs(u.y - v.y) < eps) return 0;  // 判重 
	for(int i = 0 ; i < n ; i ++)
		if(mul(l[i].a,u,v) * mul(l[i].b,u,v) >= eps) return 0;   // 叉积  
	return 1;
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i = 0 ; i < n ; i ++)
			scanf("%lf%lf%lf%lf",&l[i].a.x,&l[i].a.y,&l[i].b.x,&l[i].b.y);
		bool flag = 0;
		for(int i = 0 ; i < n && !flag ; i ++){  // 枚举 端点 
			for(int j = i+1 ; j < n && !flag ; j ++  )
				if(ok(l[i].a,l[j].a) || 
				   ok(l[i].a,l[j].b) ||
				   ok(l[i].b,l[j].a) ||
				   ok(l[i].b,l[j].b)
				)
				flag = 1;
		}
		if(flag) printf("Yes!\n");
		else printf("No!\n");
	}
}

猜你喜欢

转载自blog.csdn.net/PK__PK/article/details/83110495