[caioj]【计算几何】判断线段相交(跨立实验) 计算几何 叉积

【题意】
有n条线段(编号为1~n)(n<=10000),按1~n的顺序放在二维坐标系上(就是先放1号,再放2号……),要求输出最上面的那些线段的编号(就是没有其他线段压在它上面的那些线段)

题解:

数据较弱,可以使用暴力,但如何判断两线段相交,本题题意是用叉积判断。
基本知识:叉积>0,为逆时针转,叉积<0,为顺时针转。
如下图,
这里写图片描述
两端点为p1,p2的线段l1与两端点为p3,p4的线段l2相交时,以p1为基准点,p3转向p2的方向与p2转向p4的方向是一样的,也就是说两叉积之积大于0。但这还不够,还需要判断以p3为基准点的p1,p4,p2的旋转方向,因为当p1在l2的左边时,也能满足条件1。


还有特殊情况,就是线段的一个端点在另一条线段所在的直线上,那么此时叉积为0,此时判断该点是否在线段上即可。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node{double x,y;};
struct line{node p1,p2;}L[10010];
double multi(node p1,node p2,node p0)
{
    double x1,y1,x2,y2;
    x1=p1.x-p0.x;
    y1=p1.y-p0.y;
    x2=p2.x-p0.x;
    y2=p2.y-p0.y;
    return x1*y2-x2*y1;
}
int n;
bool check(line l1,line l2)
{
    node p1,p2,p3,p4;
    p1=l1.p1;p2=l1.p2;p3=l2.p1;p4=l2.p2;
    if(multi(p3,p2,p1)*multi(p2,p4,p1)>0.0&&multi(p1,p4,p3)*multi(p4,p2,p3)>0.0)return true;
    if(multi(p1,p3,p4)==0.0&&min(p3.x,p4.x)<=p1.x&&p1.x<=max(p3.x,p4.x))return true;
    if(multi(p2,p3,p4)==0.0&&min(p3.x,p4.x)<=p2.x&&p2.x<=max(p3.x,p4.x))return true;
    if(multi(p3,p1,p2)==0.0&&min(p1.x,p2.x)<=p3.x&&p3.x<=max(p1.x,p2.x))return true;
    if(multi(p4,p1,p2)==0.0&&min(p1.x,p2.x)<=p4.x&&p4.x<=max(p1.x,p2.x))return true;
    return false;
}
int main()
{
    int ans[10010],l=0;
    bool f[10010];
    memset(f,true,sizeof(f));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%lf%lf%lf%lf",&L[i].p1.x,&L[i].p1.y,&L[i].p2.x,&L[i].p2.y);
    for(int i=1;i<n;i++)
    for(int j=i+1;j<=n;j++)
    if(check(L[i],L[j])){f[i]=false;break;}//重要优化!!!
    for(int i=1;i<=n;i++)
    if(f[i])ans[++l]=i;
    for(int i=1;i<=l;i++)printf("%d ",ans[i]);
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值