题目来源: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,共线。我比较笨,无法理解,只好死记硬背。。)满足一条参考线还不行,必须两条线断都做过一次参考线才可以判断两条线段相交。例如:
图中如果S1作为参考线 那么S2的两个端点满足以上所述,但是两线段并不相交。所以要考虑将两条线段都要做一次参考线段。
如果满足了上述条件,我说他就一定相交。那么,问题来了,如果有一点共线呢???????
对于第二种共线你会发现,虽然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