POJ 3304 Segments (叉乘判断线段相交)
Posted 00isok
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3304 Segments (叉乘判断线段相交)相关的知识,希望对你有一定的参考价值。
<题目链接>
题目大意:
给出一些线段,判断是存在直线,使得该直线能够经过所有的线段。、
解题思路:
如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交。
如果存在这么一条直线,那么该直线一定能够移成经过两个端点的形式。枚举所有线段的两个端点,判断该直线和所有线段是否相交即可。
#include <iostream> #include <math.h> #include <cstdio> using namespace std; #define MAXM 110 #define EPS 1e-8 //10的负8次方 typedef struct{ double x1,y1,x2,y2; }Segment; //线段 Segment segment[MAXM]; int n; double distance(double x1,double y1,double x2,double y2){ //计算两点之间距离 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double corss(double x1,double y1,double x2,double y2,double x,double y){ return (x2-x1)*(y-y1)-(x-x1)*(y2-y1); //返回 (x2-x1,y2-y1) , (x-x1,y-y1)这两个向量的叉乘 } //根据的是(x,y)叉乘(b.x,b.y)=(x*b.y-y*b.x)公式;这个公式也可以通过三维向量叉乘的行列式得到,只不过要将这两个向量的Z坐标看成0 bool judge(double x1,double y1,double x2,double y2){ int i; if(distance(x1,y1,x2,y2)<EPS) return 0; for(i=0;i<n;i++){ //之所以是>ERS(ERS为无穷小),是因为若当前线段有一个端点是该分割线段的一个端点,此时答案应该是0,然而实际上0也是可以的,所以将ERS设为无穷小 if(corss(x1,y1,x2,y2,segment[i].x1,segment[i].y1)*corss(x1,y1,x2,y2,segment[i].x2,segment[i].y2)>EPS) return 0; //判断segment线段的两个端点是否置于该直线的两端 } return 1; } int main(){ int t,i,j,flag; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=0;i<n;i++) scanf("%lf%lf%lf%lf",&segment[i].x1,&segment[i].y1,&segment[i].x2,&segment[i].y2); if(n==1) {printf("Yes! ");continue;} flag=0; for(i=0;i<n && !flag;i++){ for(int j=i+1;j<n && !flag;j++){ //以任意两条线段的两个端点构成分割线,只要任意一条这样的分割线能够经过每一条线段,那么输出Yes if(judge(segment[i].x1,segment[i].y1,segment[j].x1,segment[j].y1) || judge(segment[i].x1,segment[i].y1,segment[j].x2,segment[j].y2) || judge(segment[i].x2,segment[i].y2,segment[j].x1,segment[j].y1) || judge(segment[i].x2,segment[i].y2,segment[j].x2,segment[j].y2)) flag=1; } } if(flag) printf("Yes! "); else printf("No! "); } return 0; }
2018-08-01
以上是关于POJ 3304 Segments (叉乘判断线段相交)的主要内容,如果未能解决你的问题,请参考以下文章
POJ 3304 Segments [计算几何,判断直线和线段相交]