哈理工OJ 1579 又见线段相交【计算几何】

又见线段相交
Time Limit: 1000 MSMemory Limit: 10240 K
Total Submit: 81(39 users)Total Accepted: 41(37 users)Rating: Special Judge: No
Description

给定线段P1P2P1P2是线段的两端点,且不重合)、P3P4P3P4是线段的两端点,且不重合),判断P1P2P3P4是否相交。

P1P2P3P4相交,即指仅存在一个点P,该交点不能是线段的端点。

Input

输入数据有多组,第一行为测试数据的组数N,下面包括2N行,每组测试数据含2行,第一行为P1P2的坐标值,第二行为P3P4的坐标值,比如下面的数据

表示P1P2P3P4的坐标分别为:P10,0),P21,1),P32,2),P43,3

Output
判断每组数据中的线段P1P2P3P4是否相交,如果相交输出交点坐标,输出用小数表示,精确到小数点后两位,否则输出NO。每组数据输出占一行。
Sample Input

3

0 0 1 1

2 2 3 3

0 0 2 0

0 0 1 3

0 0 1 1

0 1 1 0

Sample Output

NO

NO

(0.50,0.50)

Hint
两线段相交分为规范相交非规范相交 “规范相交指的是两条线段恰有唯一一个不是端点的公共点;而如果一条线段的一个端点在另一条线段上,或者两条线段部分重合,则视为非规范相交,本题是规范相交  定义点坐标类型时需用double

这里边比裸线段相交的题多了两个内容:

1.规范相交

2.计算相交的点的位子

相信大家计算相交点的位子是会的,这里就不重点说明了,这里说一下整体的思路,和规范相交的问题:
首先,无论是规范相交还是非规范相交,一旦是相交了,那么一定是通过了快速排斥试验以及跨立试验的、所以我们这里先判断两条线段是否相交、如果不相交、结束。

这里对应部分代码详解:

bool judge(dian a,dian b,dian c,dian d )
{
    if(min(a.x,b.x)>max(c.x,d.x)||min(a.y,b.y)>max(c.y,d.y)||min(c.x,d.x)>max(a.x,b.x)||min(c.y,d.y)>max(a.y,b.y))//快速排斥试验
    return false;
    double u,v,w,z;
    u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);//c.b.a//u的正负表示bc在ab的顺时针方向还是逆时针方向.
    v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y);//d.b.a//同理
    w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y);//a.d.c
    z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);//b.d.c
    return (u*v<=0.00000001 && w*z<=0.00000001);//如果u*v<=<span style="font-family: Arial, Helvetica, sans-serif;">0.00000001,那么说明点c,d在线段ab两端,同理,w*z也是一样<span style="white-space:pre">									</span>    }</span>
然后就是判断这个相交是规范相交还是非规范相交,这里我们知道,如果三个点共线了,那么就说明不是规范相交、结束。而且我们还知道,三点叉乘==0的时候 ,说明三点共线了、这里是判断是否为规范相交的代码:

int segment(dian p1,dian p2,dian p3)
{
    if((p3.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p3.y-p1.y)==0)
        return 1;//表示这就不是规范相交
    else
        return 0;
}
最后上完整的AC代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
struct dian
{
    double  x,y;
}p[4];
bool judge(dian a,dian b,dian c,dian d )
{
    if(min(a.x,b.x)>max(c.x,d.x)||min(a.y,b.y)>max(c.y,d.y)||min(c.x,d.x)>max(a.x,b.x)||min(c.y,d.y)>max(a.y,b.y))
    return false;
    double u,v,w,z;
    u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);//c.b.a//u的正负表示bc在ab的顺时针方向还是逆时针方向.
    v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y);//d.b.a//同理
    w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y);//a.d.c
    z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);//b.d.c
    return (u*v<=0.00000001 && w*z<=0.00000001);
}
int segment(dian p1,dian p2,dian p3)
{
    if((p3.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p3.y-p1.y)==0)
        return 1;
    else
        return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        double  a,b,c,d;
        double  e,f,g,h;
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f,&g,&h);
        p[0].x=a;
        p[0].y=b;
        p[1].x=c;
        p[1].y=d;
        p[2].x=e;
        p[2].y=f;
        p[3].x=g;
        p[3].y=h;
        if(judge(p[0],p[1],p[2],p[3]))
        {
            if(segment(p[0],p[1],p[2])||segment(p[0],p[1],p[3]))
            {
                printf("NO\n");

            }
            else
            {
                double k1=(p[1].y-p[0].y)/(p[1].x-p[0].x);
                double k2=(p[3].y-p[2].y)/(p[3].x-p[2].x);
                double b1=p[1].y-k1*p[1].x;
                double b2=p[3].y-k2*p[3].x;
                double x=(b2-b1)/(k1-k2);
                double y=k1*x+b1;
                printf("(%.2lf,%.2lf)\n",x,y);
            }
        }
        else
        {
            printf("NO\n");
        }
    }
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值