51Nod 1264:线段相交(计算几何)

题目链接: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;
}







你可能感兴趣的:(ACM_数论,Online,Judge,51Nod)