Segment Intersections: Manhattan Geometry(线段相交问题)

Segment Intersections: Manhattan Geometry

For given nn segments which are parallel to X-axis or Y-axis, find the number of intersections of them.

Input

In the first line, the number of segments nn is given. In the following nn lines, the ii-th segment is given by coordinates of its end points in the following format: 

x1y1x2y2x1y1x2y2 

The coordinates are given in integers.

Output

Print the number of intersections in a line.

Constraints

  • 1n100,0001≤n≤100,000
  • 1,000,000,000x1,y1,x2,y21,000,000,000−1,000,000,000≤x1,y1,x2,y2≤1,000,000,000
  • Two parallel segments never overlap or touch.
  • The number of intersections 1,000,000≤1,000,000

Sample Input 1

6
2 2 2 5
1 3 5 3
4 1 4 4
5 2 7 2
6 1 6 3
6 5 6 7

Sample Output 1

3

现在给出n条平行于x轴或者y轴的线段,请输出交点数

可以通过平面扫描(sweep)进行高效求解。平面扫描算法的思路是将一条与x轴(或者y轴)平行的直线向上(向右)平行移动,在移动的过程中寻找交点。这条直线称为扫描线。

扫描线并不是按照固定的间隔进行逐行扫描,而是每次遇到平面上线段的端点时停止移动,然后检查该位置的线段交点。

在扫描移动过程中,算法会将扫描线穿过的垂直线段(与y轴平行)临时记录下来,等到扫描线与水平线段(与x轴平行)重叠时,检查水平线段的范围内是否存在垂直线段上的点,然后将这些点作为交点输出。


平面扫描:

1.将已输入线段的端点按y坐标升序排列,添加至表EP

2.将二叉搜索树T置为空

3.按顺序取出EP的端点(相当于让扫描线自下而上移动),进行以下处理

  如果取出的端点为垂直线段的上端点,则从T中删除该线段的x坐标

  如果取出的端点为垂直线段的下端点,则将该线段的x坐标插入T

  如果取出的端点为水平线段的左端点(扫描线与水平线段重合时),将该水平线段的两个端点作为搜索范围,输出T中包含的值(即垂直线段的x坐标)。

复杂度分析:使用平衡二叉搜索树后,一次搜索操作的复杂度是O(logn),由于这个值小于2n,所以二叉树带来的复杂度为O(nlogn)。算法整个的复杂度还与交点数k有关,所以总的复杂度为O(nlogn+k)。

#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3

struct point{
    double x,y;
    point(){}
    point(double x,double y):x(x),y(y){}
    point operator + (point &p){
        return point(x+p.x,y+p.y);
    }
    point operator - (point &p){
        return point(x-p.x,y-p.y);
    }
    point operator * (double k){
        return point(x*k,y*k);
    }
    point operator / (double k){
        return point(x/k,y/k);
    }
};

struct segment{
    point p1,p2;
};

struct endpoint{
    point p;
    int seg,st;
    endpoint(){}
    endpoint(point p,int seg,int st):p(p),seg(seg),st(st){}
    bool operator < (const endpoint &ep)const{
        if(p.y==ep.p.y){
            return st<ep.st;//y相同时,按照下断点,左端点,右端点,上端点的顺序排列
        }else{
            return p.y<ep.p.y;
        }
    }
};
endpoint ep[2*maxn];

int manhattanIntersection(vector<segment>s)
{
    int n=s.size();
    for(int i=0,k=0;i<n;i++){
        if(s[i].p1.y==s[i].p2.y){
            if(s[i].p1.x>s[i].p2.x){
                swap(s[i].p1,s[i].p2);
            }
        }else if(s[i].p1.y>s[i].p2.y){
            swap(s[i].p1,s[i].p2);
        }
        if(s[i].p1.y==s[i].p2.y){
            ep[k++]=endpoint(s[i].p1,i,LEFT);
            ep[k++]=endpoint(s[i].p2,i,RIGHT);
        }else{
            ep[k++]=endpoint(s[i].p1,i,BOTTOM);
            ep[k++]=endpoint(s[i].p2,i,TOP);
        }
    }
    sort(ep,ep+(2*n));
    set<int>bt;
    bt.insert(1000000001);
    int cnt=0;
    for(int i=0;i<2*n;i++){
        if(ep[i].st==TOP){
            bt.erase(ep[i].p.x);
        }else if(ep[i].st==BOTTOM){
            bt.insert(ep[i].p.x);
        }else if(ep[i].st==LEFT){
            set<int>::iterator b=bt.lower_bound(s[ep[i].seg].p1.x);
            set<int>::iterator e=bt.upper_bound(s[ep[i].seg].p2.x);
            cnt+=distance(b,e);
        }
    }
    return cnt;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值