poj3304 Segments 计算几何

题目大意:

给出n条线段两个端点的坐标,问所有线段投影到一条直线上,
如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。

解题思路:

如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,
问题转化为问是否存在一条线和所有线段相交

若存在一条直线与所有线段相交,此时该直线必定经过这些线段的某两个端点,所以枚举任意两个端点即可。
这里要主要的地方就是,题目说如果两个点的距离小于1e-8就等价于一点,所以要考虑重点 

关于coross函数:

1.若函数的返回值为0,则 (x2-x1)*(y-y1)-(x-x1)*(y2-y1);
(y-y1)/(x-x1)=(y2-y1)/(x2-x1); (直线斜率相等,k1=k2)
注意:(浮点数除法在计算的过程中会影响精度) 
过(x,y),(x1,y1)的直线(直线斜率为k1)和过(x1,y1),(x2,y2)的直线(直线斜率为k2)平行
说明 (x,y)在过 (x1,y1),(x2,y2)的直线上

2.若返回值不为0,说明 (x,y)不在过 (x1,y1),(x2,y2)的直线上

①返回值小于0,(y-y1)/(x-x1)<(y2-y1)/(x2-x1);即 k1<k2


②返回值大于0,(y-y1)/(x-x1)>(y2-y1)/(x2-x1);即 k1>k2 

关于judge函数:

若(x1,y1),(x2,y2)不重合,判断过(x1,y1),(x2,y2)的直线是否和线段seg[i]相交 
1.coross(x1,y1,x2,y2,seg[i].x1,seg[i].y1)*coross(x1,y1,x2,y2,seg[i].x2,seg[i].y2)
若乘积的符号为正,则说明 过(x1,y1),(x2,y2)的直线和线段seg[i]不相交 

2.coross(x1,y1,x2,y2,seg[i].x1,seg[i].y1)*coross(x1,y1,x2,y2,seg[i].x2,seg[i].y2)

若乘积的符号为负,则说明 过(x1,y1),(x2,y2)的直线和线段seg[i]相交 


#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAX=105;
const double EPS=1e-8;//EPS相当于0
struct node{
	double x1,y1,x2,y2;
}seg[MAX];
int n;
double distance(double x1,double y1,double x2,double y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

//若两条直线斜率相等,则不相交 
double coross(double x1,double y1,double x2,double y2,double x,double y)
{
	return (x2-x1)*(y-y1)-(x-x1)*(y2-y1); //叉积 
}

//判断经过点(x1,y1),(x2,y2)的直线是否和所有的线段相交 
bool judge(double x1,double y1,double x2,double y2)
{
	if(distance(x1,y1,x2,y2)<EPS)	return 0;//两点重合 
	for(int i=0;i<n;i++)
	{
	if(coross(x1,y1,x2,y2,seg[i].x1,seg[i].y1)*
	coross(x1,y1,x2,y2,seg[i].x2,seg[i].y2)>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",&seg[i].x1,&seg[i].y1,&seg[i].x2,&seg[i].y2);						
	if(n==1){
		printf("Yes!\n");continue;
	}
		bool ans=0;
		for(int i=0;i<n&&!ans;i++){
			for(int j=i+1;j<n&&!ans;j++){
				if(
				judge(seg[i].x1,seg[i].y1,seg[j].x1,seg[j].y1)||
				judge(seg[i].x1,seg[i].y1,seg[j].x2,seg[j].y2)||
				judge(seg[i].x2,seg[i].y2,seg[j].x1,seg[j].y1)||
				judge(seg[i].x2,seg[i].y2,seg[j].x2,seg[j].y2)
				)
				ans=1;
			}
		}
		if(ans) printf("Yes!\n");  
        else printf("No!\n");  
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/80158612