题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1264
题目给出两条线段让求两线段有没有交点,有重合部分也算有交点。
思路简单就是写起来有点麻烦。
已知直线上两点坐标(x1,y1),(x2,y2)。设直线上有一点(x,y)
则(y-y1)/(x-x1) = (y-y2)/(x-x2),可以化成下面的式子。
(y2-y1)*x + (x1-x2)*y + y1*x2-x1*y2 = 0
已知直线的一般方程使A*x+B*y+C = 0,所以可以知道
A = y2-y1
B = x1-x2
C = y1*x2-x1*y2
因此我们可以求出两条线段所在直线的方程为:
A1*x+B1*y+C1 = 0;
A2*x+B2*y+C2 = 0;
我们先考虑两条线段所在直线平行的情况,平行的话,一种说明两直线无交点,
一种说明两直线重合,所以先判断平行,先看是否重合,
判断直线重合的方法:把点1点2,带入点3点4的直线方程看是否成立。
或把点3点4,带入点1,点2的直线方程看是否成立。
如果成立的话,首先说明点1,点2,点3,点4是在一条直线上。
那么我们就判断线段是否重合。
判断的方法是:看点1,2坐标是否在点3,点4间。看点3,4坐标是否在
点1,2间,满足4个条件中的任意一个,说明线段重合。
否则线段不重合。
如果发现点1点2,点3,点4不在同一直线上,而且他们还平行了。
则绝对无焦点。
然后连理直线方程,求交点坐标。
方程1-方程2:
(A1-A2)*x + (B1-B2)*y + (C1-C2) = 0;
如果(A1-A2)=0,则我们表示出y。然后求x,在求出y
如果(B1-B2)=0,则我们表示出x,然后求y,在求出x
注意不可能A1 = A2 && B1=B2。
因为这样的条件属于平行的,我们已经判断过了。所以走到
求焦点这一步,不会出现(A1-A2)(B1-B2)同时为0.
PS:这个题目测试数据弱不说,还不严谨,题目说了线段重合也认为相交,
然而它的后台竟然没这种测试数据,因为我第一次提交的代码就缺少考虑这种
情况,然而AC了,后来我写这篇博客的时候,我一看自己代码,不对有BUG,我这样
写过不了重合线段哪种数据。测了 0 0 1 1 0 0 3 3 这组数据果然输出了No,我以为当时
我看错了,我又重新提交,发现还是AC了。不过奔着严谨的态度,我还是补充代码把
判断重合的条件给加上了。下面的代码就是完全正确的代码。
AC代码:
#include
#include
#include
#include
#define eps 1e-8
using namespace std;
struct Point
{
double x,y;
}P[4];
struct Line
{
double A,B,C;
}L[4];
///求直线方程
struct Line getLineFunction(Point p1,Point p2)
{
struct Line L1;
L1.A = p2.y-p1.y;
L1.B = p1.x-p2.x;
L1.C = p1.y*p2.x-p1.x*p2.y;
return L1;
};
///判断重合,已知四点共线,只需要判断点的坐标关系即可
bool chonghe()
{
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
bool flag4 = false;
if(P[0].x>=min(P[2].x,P[3].x)&&P[0].x<=max(P[2].x,P[3].x)&&P[0].y>=min(P[2].y,P[3].y)&&P[0].y<=max(P[2].y,P[3].y))
{
flag1 = true;
}
if(P[1].x>=min(P[2].x,P[3].x)&&P[1].x<=max(P[2].x,P[3].x)&&P[1].y>=min(P[2].y,P[3].y)&&P[1].y<=max(P[2].y,P[3].y))
{
flag2 = true;
}
if(P[2].x>=min(P[0].x,P[1].x)&&P[2].x<=max(P[0].x,P[1].x)&&P[2].y>=min(P[0].y,P[1].y)&&P[2].y<=max(P[0].y,P[1].y))
{
flag3 = true;
}
if(P[3].x>=min(P[0].x,P[1].x)&&P[3].x<=max(P[0].x,P[1].x)&&P[3].y>=min(P[0].y,P[1].y)&&P[3].y<=max(P[0].y,P[1].y))
{
flag4 = true;
}
if(flag1 || flag2 || flag3 || flag4)
return true;
else
return false;
}
///求是否有焦点
bool haveIntersection(Line L1,Line L2)
{
Point p;
if(L1.B*L2.A == L2.B*L1.A) ///斜率相同
{
if(L2.A*P[0].x+L2.B* P[0].y+L2.C==0 && L2.A*P[1].x+L2.B*P[1].y+L2.C==0)
{
if(chonghe())
return true;
else
return false;
}
return false;
}
if(L1.A==L2.A && L1.A==0) return false; ///多余了这两句,一个是斜率不存在的情况,一个是斜率为1的情况。
if(L1.B==L2.B && L1.B==0) return false;
if(L1.A == L2.A) ///连理一般直线方程解出x,y
{
p.y = (L1.C-L2.C)/(L2.B-L1.B);
p.x = (-L1.C-L1.B*p.y)/L1.A;
}
else if(L1.B == L2.B)
{
p.x = (L1.C-L2.C)/(L2.A-L1.A);
p.y = (-L1.C-L1.A*p.x)/L1.B;
}
else
{
p.y = (L1.A*L2.C-L1.C*L2.A)/(L2.A*L1.B-L1.A*L2.B);
p.x = (-L1.C-L1.B*p.y)/L1.A;
}
///判断焦点是否在两个线段上
if(p.x>=min(P[0].x,P[1].x)&&p.x<=max(P[0].x,P[1].x)&&p.y>=min(P[0].y,P[1].y)&&p.y<=max(P[0].y,P[1].y))
{
if(p.x>=min(P[2].x,P[3].x)&&p.x<=max(P[2].x,P[3].x)&&p.y>=min(P[2].y,P[3].y)&&p.y<=max(P[2].y,P[3].y))
return true;
else
return false;
}
return false;
};
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
for(int i = 0; i < 4; i++)
scanf("%lf%lf",&P[i].x,&P[i].y);
L[0] = getLineFunction(P[0],P[1]);
L[1] = getLineFunction(P[2],P[3]);
if(haveIntersection(L[0],L[1]))
printf("Yes\n");
else
printf("No\n");
}
return 0;
}