• 【计算几何】判断线段相交(跨立实验)


    题意:有n条线段(编号为1n),按1n的顺序放在二维坐标系上(就是先放1号,再放2号……),要求输出最上面的那些线段的编号。(就是没有其他线段压在它上面的那些线段)
    注意:有交点即为被压。

    1.叉积

    判断线段相交需要有关于叉积(外积,向量积)的预备知识。
    a×b=a×b×sinθvec{a} imes vec{b}=|vec{a}| imes |vec{b}| imes sin heta
    a(x1,y1),b(x2,y2),x1y2x2y1x1y2x2y1abvec{a}可以表示为(x1,y1),vec{b}可以表示为(x2,y2),则向量积的模(大小)为|x1*y2-x2*y1|,而我们要用的只是由x1*y2-x2*y1的正负判断两个向量的位置关系(正表示vec{a}由逆时针旋转更容易得到)vec{b}
    (不用会证明)

    性质:设两向量abvec{a},vec{b}的叉积的模为x。则有:
    若x>0,则abvec{a}到vec{b}的转向为逆时针。
    若x=0,则两向量的方向在同一直线上。
    否则,abvec{a}到vec{b}的转向为顺时针。
    (证明不用会)

    2.跨立实验

    在这里插入图片描述
    如图,AB,CDoverrightarrow{AB},overrightarrow{CD}两个向量如果相交(交点不是向量端点),
    当且仅当A>D>BB>C>AA->D->B的方向等于B->C->A的方向并且
    C>A>DD>B>CC->A->D等于D->B->C。

    特别地,当两个向量的交点为一个向量的一个端点,则通过叉积大小等于0来判断。
    注意:上面纯属扯淡,主要看代码。

    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=1e4+10;
    struct node{
    	double x,y;
    };
    struct line{
    	node p1,p2;
    }list[N];
    double mult(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;
    }
    bool check(line l1,line l2)
    {
    	node p1=l1.p1;
    	node p2=l1.p2;
    	node p3=l2.p1;
    	node p4=l2.p2;
    	if(mult(p3,p2,p1)*mult(p2,p4,p1)>0&&mult(p1,p4,p3)*mult(p4,p2,p3)>0)return true;
    	if(	(mult(p3,p4,p1)==0&&min(p3.x,p4.x)<=p1.x&&p1.x<=max(p3.x,p4.x)&&min(p3.y,p4.y)<=p1.y&&p1.y<=max(p3.y,p4.y)) ||
    		(mult(p3,p4,p2)==0&&min(p3.x,p4.x)<=p2.x&&p2.x<=max(p3.x,p4.x)&&min(p3.y,p4.y)<=p2.y&&p2.y<=max(p3.y,p4.y)) ||
    		(mult(p1,p2,p3)==0&&min(p1.x,p2.x)<=p3.x&&p3.x<=max(p1.x,p2.x)&&min(p1.y,p2.y)<=p3.y&&p3.y<=max(p1.y,p2.y))	||
    		(mult(p1,p2,p4)==0&&min(p1.x,p2.x)<=p4.x&&p4.x<=max(p1.x,p2.x)&&min(p1.y,p2.y)<=p4.y&&p4.y<=max(p1.y,p2.y)) ) return true;
    	return false;
    }
    bool v[N];
    int b[N];
    int main()
    {
    	int n;scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lf%lf%lf%lf",&list[i].p1.x,&list[i].p1.y,&list[i].p2.x,&list[i].p2.y);
    	int tot=0;
    	for(int i=1;i<n;i++)
    		for(int j=i+1;j<=n;j++)
    		{
    			if(check(list[i],list[j]))
    			{
    				v[i]=1;
    				break;
    			}
    		}
    	for(int i=1;i<=n;i++)if(!v[i])b[++tot]=i;
    	for(int i=1;i<tot;i++)printf("%d ",b[i]);
    	printf("%d
    ",b[tot]);
    	return 0;
    }/*
    提供一个数据 
    2
    0 0 0 1
    0 2 0 3
    */
    
    
  • 相关阅读:
    ngix反向代理-之反向
    redux和flux究竟有什么不同, 说点自己的理解
    npm发包记录
    由一个聚焦-focus-事件异常跟踪引起的总结
    git查看分支的几个方法
    test-your-mind-快速测试自己的代码
    contos7 yum安装php7.2与swoole (2)
    php_ thinkphp 时间回滚
    30个php操作redis常用方法代码例子
    redis_php 安装与卸载
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373919.html
Copyright © 2020-2023  润新知