POJ 1269 Intersecting Lines 判断直线间的状态(平行、重合、相交于一点)

Intersecting Lines
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 8593 Accepted: 3900

Description

We all know that a pair of distinct points on a plane defines a line and that a pair of lines on a plane will intersect in one of three ways: 1) no intersection because they are parallel, 2) intersect in a line because they are on top of one another (i.e. they are the same line), 3) intersect in a point. In this problem you will use your algebraic knowledge to create a program that determines how and where two lines intersect. 
Your program will repeatedly read in four points that define two lines in the x-y plane and determine how and where the lines intersect. All numbers required by this problem will be reasonable, say between -1000 and 1000. 

Input

The first line contains an integer N between 1 and 10 describing how many pairs of lines are represented. The next N lines will each contain eight integers. These integers represent the coordinates of four points on the plane in the order x1y1x2y2x3y3x4y4. Thus each of these input lines represents two lines on the plane: the line through (x1,y1) and (x2,y2) and the line through (x3,y3) and (x4,y4). The point (x1,y1) is always distinct from (x2,y2). Likewise with (x3,y3) and (x4,y4).

Output

There should be N+2 lines of output. The first line of output should read INTERSECTING LINES OUTPUT. There will then be one line of output for each pair of planar lines represented by a line of input, describing how the lines intersect: none, line, or point. If the intersection is a point then your program should output the x and y coordinates of the point, correct to two decimal places. The final line of output should read "END OF OUTPUT".

Sample Input

5
0 0 4 4 0 4 4 0
5 0 7 6 1 0 2 3
5 0 7 6 3 -6 4 -3
2 0 2 27 1 5 18 5
0 3 4 0 1 2 2 5

Sample Output

INTERSECTING LINES OUTPUT
POINT 2.00 2.00
NONE
LINE
POINT 2.00 5.00
POINT 1.07 2.20
END OF OUTPUT
题目大意:

      给你 2*N 对点,每一对点可以确定一条直线,所以每一行就出给了两条由点对所确定的直线,要你去判断这两条直线的关系。平行则输出NONE,重合则输出LINE,相交于一点则输出那个交点的坐标。

解题思路:

      通过运用叉乘我们能很快的判断出是否相交,如果相交,则两次叉乘的符号会不同。因为一条直线分别跨立在另一条直线的两边,所以以一条直线的两个端点分别作到另一条直线的两个端点的矢量,这两个矢量必然会分别在该直线(矢量)的两端。当我们判断完是否相交后,就只要判断是平行还是重合了,如果是重合,那么这两次叉乘必然都等于0。如果他们是相交的,我们知道直线可以用参数方程 P + t * v 表示 (点向式,v表示向量,t表示某常数,p则为已知点)。我们设交点在第一条直线上可以用一个已知点P,矢量可以求出为v,t1未知表示,而在另外一条直线上一点Q,矢量可以求出为w , t2未知表示,我们可以列方程解出 t1 = cross(w,u) / cross(v,w) , t2 = cross(v ,u ) / cross ( v ,w )。这里的cross参数为矢量。所以我们解出t1或者t2代入点向式,就可以得出我们的交点(注意:cross ( v , w ) != 0 ,但是在题目中显然满足,想一想为什么 )。即代码中的GetLineIntersection()函数求出。

代码如下:

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
#define maxn 11
#define eps 10e-9
struct Point 
{
    double x,y;
    Point (){}
    Point ( double x,double y ) : x(x) , y(y) {}
};
typedef Point Vector; //向量只是点的别名
Point operator + ( Point A , Point B ) { return Point ( A.x + B.x , A.y + B.y ); }
Vector operator * ( Vector v, double t ) { return Vector ( v.x * t , v.y * t ); } 
struct Line
{
    Point s,e;
}line[2*maxn];



double cross ( Point a, Point b , Point o )  //叉乘的三点式
{
    return ( a.x - o.x ) * ( b.y - o.y ) - ( a.y - o.y ) * ( b.x - o.x );
}

double Cross ( Vector v , Vector w )  //叉乘的向量式
{
    return v.x * w.y - v.y * w.x;
}

Point GetLineIntersection ( Point P , Vector v , Point Q, Vector w )  //求交点函数,注意参数是根据点向式所定
{
    Vector u;
    u.x = P.x - Q.x;
    u.y = P.y - Q.y;
    double t = Cross ( w , u ) / Cross ( v , w );
    return P + v * t;
}

double mutiply( Point a , Point b , Point p , Point q ) //叉乘的四点式
{
    double x1 = b.x - a.x;
    double y1 = b.y - a.y;
    double x2 = q.x - p.x;
    double y2 = q.y - p.y;
    return x1 * y2 - x2 * y1;
}

//1 共线
//2 相交于一点
//0 平行
int check_cross ( Line a,Line b )  //判断直线关系的主体
{
    if ( fabs( mutiply ( a.s , a.e , b.s , b.e ) ) < eps ) 
    {
        double t1 = cross ( a.s , b.e , a.e );
        double t2 = cross ( a.s , b.s , a.e );
        if ( fabs ( t1 ) < eps && fabs ( t2 ) < eps ) 
            return 1;
        else return 0;
    }
    else return 2;
}

int main()
{
    int n;
    scanf ( "%d" , &n );
    printf ( "INTERSECTING LINES OUTPUT\n" );
    for ( int i = 0 ; i < n ; i ++ )
    {
        scanf ( "%lf %lf %lf %lf %lf %lf %lf %lf" , &line[i].s.x , &line[i].s.y , &line[i].e.x , &line[i].e.y , &line[i+n].s.x , &line[i+n].s.y , &line[i+n].e.x ,&line[i+n].e.y );
        if ( check_cross ( line[i] , line[i+n] ) == 0 )
        {
            printf ( "NONE\n" );
        }
        else if ( check_cross ( line[i] , line[i+n] ) == 1 )
        {
            printf ( "LINE\n" );
        }
        else
        {
            Vector u,v;
            u.x = line[i].e.x - line[i].s.x;
            u.y = line[i].e.y - line[i].s.y;
            v.x = line[i+n].e.x - line[i+n].s.x;
            v.y = line[i+n].e.y - line[i+n].s.y;
            Point ans = GetLineIntersection ( line[i].e , u , line[i+n].e , v );
            printf ( "POINT %.2lf %.2lf\n" , ans.x , ans.y );
        }
    }
    printf ( "END OF OUTPUT\n" );
    return 0;
}

技巧总结:

      对于直线的相交判定我们可能已经很熟悉了,在我的前两篇博文中已经有详细的描述。对于直线的交点我们必须要尊崇公式,计算几何的题目务必牢记公式和模板,我们在平时所要完成的任务就是确保我们选择的公式和模板一定能解得正确的答案,这一点提醒自己和一起奋斗的ACMer们。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值