[计算几何]判断线段相交(跨立实验)

欢迎大家访问我的老师的OJ———caioj.cn

题面描述

传送门

思考

看完视频之后,

发现SCY讲得真(mo)好(hu)。

下面我来总结一下规律:
在这里插入图片描述
在这里插入图片描述

我们以 p 1 p_1 p1为原点,判断 p 3 p_3 p3 p 2 p_2 p2, p 2 p_2 p2 p 4 p_4 p4是否是同一个方向旋转(注意是 p 3 p_3 p3 p 2 p_2 p2 p 2 p_2 p2 p 4 p_4 p4),可以利用叉乘来理解。

p 3 p_3 p3为原点的情况同理。

像上图就很好理解。

主要处理下列这种特殊情况。

在这里插入图片描述
这是以 p 1 p_1 p1为原点, p 2 , p 3 p_2,p_3 p2,p3共点,它们叉乘之积为0。

我们再来一种普遍情况。
在这里插入图片描述
类似这样的, p 2 , p 3 p_2,p_3 p2,p3共线,或其它两点或两点以上共线的,我们肯定有一个两两叉乘之积为 0 0 0的结果,那么可以判断,现作为原点(即SCY中的标准点),以上图为例,我们可以判断

if(mul(p3,p2,p1)==0&&mymin(p1.x,p2.x)<=p3.x&&mymax(p1.x,p2.x)>=p3.x)return true;

p 3 . x p_3.x p3.x是否在 [ m i n ( p 1 . x , p 2 . x ) , m a x ( p 1 . x , p 2 . x ) ] [min(p_1.x,p_2.x),max(p_1.x,p_2.x)] [min(p1.x,p2.x),max(p1.x,p2.x)]这个范围之中,证明它是否有被覆盖。

但是这样还不行。

比如说:

在这里插入图片描述
所以我们还要再判断一下 y y y是否在范围才行。

AC code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
const int N=1e4+10;
struct node{double x,y;};
struct line{node p1,p2;}a[N];
double mul(node p1,node p2,node p0)
{
    double x1=p1.x-p0.x,x2=p2.x-p0.x;
    double y1=p1.y-p0.y,y2=p2.y-p0.y;
    return x1*y2-x2*y1;
}
double mymin(double x,double y){return x<y?x:y;}
double mymax(double x,double y){return x>y?x:y;}
bool pd(line l1,line l2)
{
    node p1=l1.p1;
    node p2=l1.p2;
    node p3=l2.p1;
    node p4=l2.p2;
    if(mul(p3,p2,p1)*mul(p2,p4,p1)>0&&mul(p1,p4,p3)*mul(p4,p2,p3)>0)return true;
    if(mul(p3,p2,p1)==0&&mymin(p1.x,p2.x)<=p3.x&&mymax(p1.x,p2.x)>=p3.x&&mymin(p1.y,p2.y)<=p3.y&&mymax(p1.y,p2.y)>=p3.y)return true;
    if(mul(p2,p4,p1)==0&&mymin(p1.x,p2.x)<=p4.x&&mymax(p1.x,p2.x)>=p4.x&&mymin(p1.y,p2.y)<=p4.y&&mymax(p1.y,p2.y)>=p4.y)return true;
    if(mul(p1,p4,p3)==0&&mymin(p3.x,p4.x)<=p1.x&&mymax(p3.x,p4.x)>=p1.x&&mymin(p3.y,p4.y)<=p1.y&&mymax(p3.y,p4.y)>=p1.y)return true;
    if(mul(p4,p2,p3)==0&&mymin(p3.x,p4.x)<=p2.x&&mymax(p3.x,p4.x)>=p2.x&&mymin(p3.y,p4.y)<=p2.y&&mymax(p3.y,p4.y)>=p2.y)return true;
    return false;
}
int b[N];
int main()
{
    int n;scanf("%d",&n);int tot=0;
    for(int i=1;i<=n;i++)scanf("%lf%lf%lf%lf",&a[i].p1.x,&a[i].p1.y,&a[i].p2.x,&a[i].p2.y);
    for(int i=1;i<=n;i++)
    {
        bool bk=true;
        for(int j=i+1;j<=n;j++)
            if(pd(a[i],a[j])){bk=false;break;}
        if(bk)b[++tot]=i;
    }
    for(int i=1;i<tot;i++)printf("%d ",b[i]);
    printf("%d\n",b[tot]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值