关于线段相交问题

题目来源:http://icpc.upc.edu.cn/problem.php?cid=1762&pid=2

题目描述

给定N个线段。求有交点的线段对数。
保证没有两条线段共线

 

输入

一行一个整数N,表示线段的个数
第2~N+1行,每行四个实数,x1,y1,x2,y2,表示线段的两个端点(x1,y1)和(x2,y2)

 

输出

一行一个整数,表示有交点的线段对数。

 

样例输入

3
0.00 0.00 1.00 1.00
0.00 1.00 1.00 0.00
0.00 0.00 1.00 0.00

样例输出

3

 

提示

(0,0)(1,1)和(0,1)(1,0)有交点
(0,0)(1,1)和(0,0)(1,0)有交点
(0,1)(1,0)和(0,0)(1,0)有交点

对于100%的数据,N≤100
点的坐标范围(−10000,10000)

本道题目说了数据最多100组  所以直接暴力判断就可以了。。

难点就在于如何判断两条线段相交呢??????????????

我们都知道两条直线相交怎么判断,呢个很简单,但是对于本题一点用都没有。。。

我自己对线段相交的理解:

          如果两条线段相交的话,那么先选一条线段作为参考线,另一条线段的两个端点必须在参考线段的两侧,当然也可以有一个端点在这条参考线上,不可能两个端点都在参考线上  题目有说明。当然我们先看最简单的情况,两个端点必须在参考线的两侧,也就是说参考线的两个端点,加上另一条线段的其中一个端点为逆时针,加上另一个端点为顺时针。(三点顺逆时针问题可以用向量的叉乘积来判断 m=(x2-x1)*(y3-y1)-(y2-y1)*(x3-x1) 如果m>0则为逆时针,小于0为顺时针,等于0,共线。我比较笨,无法理解,只好死记硬背。。)满足一条参考线还不行,必须两条线断都做过一次参考线才可以判断两条线段相交。例如:

关于线段相交问题_第1张图片

图中如果S1作为参考线  那么S2的两个端点满足以上所述,但是两线段并不相交。所以要考虑将两条线段都要做一次参考线段。

如果满足了上述条件,我说他就一定相交。那么,问题来了,如果有一点共线呢???????

关于线段相交问题_第2张图片

对于第二种共线你会发现,虽然S2的一个端点与S1共线,但是S1的两个端点在S2的一侧,并不满足两个端点一个顺时针,一个逆时针。所以满足之前的条件后还共线的话,必然这两条线段相交。换句话说,只要不满足上述条件,一定不相交,否则,相交。

剩下的问题就是关于double的精度问题了。我也不知道具体怎么弄的,很复杂,不易理解。看完学长的博客后,学到了。遇见double时,判断0的时候就把0换成0.00000001就对了。

接下来就是代码:

#include
using namespace std;
typedef struct
{
	double x1,x2;
	double y1,y2;
}sen;
int judge(sen s1,sen s2)
{
	double m1=(s1.x2-s1.x1)*(s2.y1-s1.y1)-(s1.y2-s1.y1)*(s2.x1-s1.x1);
	double m2=(s1.x2-s1.x1)*(s2.y2-s1.y1)-(s1.y2-s1.y1)*(s2.x2-s1.x1);
	double m3=(s2.x2-s2.x1)*(s1.y1-s2.y1)-(s2.y2-s2.y1)*(s1.x1-s2.x1);
	double m4=(s2.x2-s2.x1)*(s1.y2-s2.y1)-(s2.y2-s2.y1)*(s1.x2-s2.x1);
	if(m1*m2>0.00000001||m3*m4>0.00000001)return 0;
	return 1;
}
int main()
{
    sen s[500];
    int n;
    scanf("%d",&n);
    for(int i=0;i

 

你可能感兴趣的:(总结)