HDU-1086 You can Solve a Geometry Problem too 解题报告

Description

Many geometry(几何)problems were designed in the ACM/ICPC. Andnow, I also prepare a geometry problem for this final exam. According to theexperience of many ACMers, geometry problems are always much trouble, but thisproblem is very easy, after all we are now attending an exam, not a contest :)
Give you N (1<=N<=100) segments(线段), please output the number of allintersections(交点). You should countrepeatedly if M (M>2) segments intersect at the same point.

Note:
You can assume that two segments would not intersect at more than one point. 

 

Input

Input containsmultiple test cases. Each test case contains a integer N (1=N<=100) in aline first, and then N lines follow. Each line describes one segment with fourfloat values x1, y1, x2, y2 which are coordinates of the segment’s ending. 
A test case starting with 0 terminates the input and this test case is not tobe processed.

 

Output

For each case,print the number of intersections, and one line one case.

 

Sample Input

2

0.00 0.00 1.001.00

0.00 1.00 1.000.00

3

0.00 0.00 1.001.00

0.00 1.00 1.000.000

0.00 0.00 1.000.00

0

 

Sample Output


1

3

 

       题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1086

       解法类型:向量叉乘

       解题思路:一道计算几何入门题,首先要有判断两条线段是否相交的预备知识,当然后很多方法。如把线段化为直线看交点所在的区间,或者建立向量,看线段一端点与另一线段的两端点的两个向量的夹角是否小于180°等等。这里用到一种朴实的方法,即向量叉乘判断法:                       

   判断两线段是否相交

  我们分两步确定两条线段是否相交:

  (1)快速排斥试验

    设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交。

  (2)跨立试验
    如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。具体情况如下图所示:

                                                     

       算法实现:

//STATUS:C++_AC_15MS_204K
#include<stdio.h>
int is_inter(struct Segment a,struct Segment b);     //跨立实验
int is_fxiji(struct Segment a,struct Segment b);     //快速排斥
const int MAXN=100;
struct Segment{
    double x1,y1,x2,y2;
}seg[MAXN];

int main()
{
    int i,j,n,m;
    while(scanf("%d",&n)&&n)
    {
        for(i=0;i<n;i++)
            scanf("%lf%lf%lf%lf",&seg[i].x1,&seg[i].y1,&seg[i].x2,&seg[i].y2);
        for(i=0,m=0;i<n-1;i++)
            for(j=i+1;j<n;j++){
                if(is_fxiji(seg[i],seg[j]))
                    if(is_inter(seg[i],seg[j])&&is_inter(seg[j],seg[i]))   //要分别对两直线进行跨立实验,才是两直线相交的充分必要条件
                        m++;
            }
        printf("%d\n",m);
    }
    return 0;
}

int is_inter(Segment a,Segment b)     //跨立实验
{
    double x[3],y[3];
    x[0]=a.x1-b.x2,y[0]=a.y1-b.y2,
        x[1]=b.x2-b.x1,y[1]=b.y2-b.y1,
        x[2]=a.x2-b.x1,y[2]=a.y2-b.y1;
    if((x[0]*y[1]-x[1]*y[0])*(x[2]*y[1]-x[1]*y[2])>0)return 0;
    return 1;
}

int is_fxiji(struct Segment a,struct Segment b)   //快速排斥,RT是否相交
{
    double t;
    if(a.x1>a.x2)t=a.x1,a.x1=a.x2,a.x2=t;
    if(b.x1>b.x2)t=b.x1,b.x1=b.x2,b.x2=t;
    if(b.x1>a.x2||b.x2<a.x1)return 0;
    if(a.y1>a.y2)t=a.y1,a.y1=a.y2,a.y2=t;
    if(b.y1>b.y2)t=b.y1,b.y1=b.y2,b.y2=t;
    if(b.y1>a.y2||b.y2<a.y1)return 0;
    return 1;
}






 

posted @ 2012-02-16 11:17  zhsl  阅读(138)  评论(0编辑  收藏  举报