Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 8593 | Accepted: 3900 |
Description
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
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们。