ledong_ 2023-05-22 19:54 采纳率: 100%
浏览 17
已结题

判断两折线段是否相交

折线段为LineString,即给出顺序连接线段的端点
除了暴力枚举两折线段的所有边,还有没有时间复杂度更低的算法
  • 写回答

1条回答 默认 最新

  • 码上团建 2023-05-22 20:13
    关注

    有一种基于扫描线的算法可以判断两条折线段是否相交,时间复杂度为O((n+m)log(n+m)),其中n和m分别为两条折线段的点数。下面是具体的实现思路:

    • 将两条折线段的所有端点按照x坐标从小到大排序,如果x坐标相等则按照y坐标从小到大排序。这样可以保证扫描线从左往右扫描时,每个点都是按照从左往右、从下往上的顺序依次遍历的。
    • 开始扫描线,从左往右依次扫描每个点。对于每个点,判断它是否是某条折线段的端点,如果是,则将该折线段的所有边加入到一个线段集合中。
    • 对于线段集合中的每条线段,判断它是否与其他线段相交。可以使用线段树等数据结构来维护线段集合,并在插入线段和删除线段时判断相交关系。
    • 如果存在相交的线段,则说明两条折线段相交。

    下面是一个C++的实现示例,使用了STL中的set和pair来实现线段集合:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <set>
    #include <utility>
    
    using namespace std;
    
    struct Point {
        int x;
        int y;
        Point(int x, int y): x(x), y(y) {}
    };
    
    struct Segment {
        Point p1;
        Point p2;
        Segment(Point p1, Point p2): p1(p1), p2(p2) {}
    };
    
    bool cmp(const Point& p1, const Point& p2) {
        if (p1.x != p2.x) {
            return p1.x < p2.x;
        } else {
            return p1.y < p2.y;
        }
    }
    
    bool intersect(const Segment& s1, const Segment& s2) {
        int x1 = s1.p1.x, y1 = s1.p1.y;
        int x2 = s1.p2.x, y2 = s1.p2.y;
        int x3 = s2.p1.x, y3 = s2.p1.y;
        int x4 = s2.p2.x, y4 = s2.p2.y;
        if (max(x1, x2) < min(x3, x4) || max(x3, x4) < min(x1, x2) ||
            max(y1, y2) < min(y3, y4) || max(y3, y4) < min(y1, y2)) {
            return false;
        }
        int c1 = (x2-x1)*(y3-y1) - (y2-y1)*(x3-x1);
        int c2 = (x2-x1)*(y4-y1) - (y2-y1)*(x4-x1);
        int c3 = (x4-x3)*(y1-y3) - (y4-y3)*(x1-x3);
        int c4 = (x4-x3)*(y2-y3) - (y4-y3)*(x2-x3);
        return (c1*c2 <= 0) && (c3*c4 <= 0);
    }
    
    int main() {
        // 读入两条折线段的端点
        int n, m;
        cin >> n >> m;
        vector<Point> points;
        for (int i = 0; i < n+m; i++) {
            int x, y;
            cin >> x >> y;
            points.push_back(Point(x, y));
        }
    
        // 按照x坐标从小到大排序,如果x坐标相等则按照y坐标从小到大排序
        sort(points.begin(), points.end(), cmp);
    
        // 扫描线
        set<pair<Segment, int>> segments;
        for (int i = 0; i < n+m; i++) {
            // 判断当前点是否是某条折线段的端点
            if (i > 0 && points[i].x == points[i-1].x && points[i].y == points[i-1].y) {
                continue;
            }
            int j = i+1;
            while (j < n+m && points[j].x == points[i].x && points[j].y == points[i].y) {
                j++;
            }
            if (j-i == 2) {
                // 当前点是一条线段的端点
                Segment seg(points[i], points[j-1]);
                if (i < n) {
                    // 第一条折线段
                    segments.insert(make_pair(seg, 1));
                } else {
                    // 第二条折线段
                    segments.insert(make_pair(seg, 2));
                }
            }
            i = j-1;
        }
    
        // 判断相交关系
        for (auto it1 = segments.begin(); it1 != segments.end(); it1++) {
            for (auto it2 = next(it1); it2 != segments.end(); it2++) {
                if (it1->second != it2->second && intersect(it1->first, it2->first)) {
                    cout << "Two segments intersect" << endl;
                    return 0;
                }
            }
        }
        cout << "Two segments do not intersect" << endl;
        return 0;
    }
    
    
    

    这个程序先将所有点按照x坐标从小到大排序,然后扫描线从左往右依次扫描每个点,将每条线段加入到一个set中。最后,遍历set中的所有线段,判断它们是否相交。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 6月6日
  • 已采纳回答 5月29日
  • 创建了问题 5月22日

悬赏问题

  • ¥15 r语言xlsx包下载后使用时出现了下列问题该如何解决
  • ¥15 Arcgis河网分级报错
  • ¥200 java+appium2.1+idea
  • ¥20 请帮我做一个EXE的去重TXT文本
  • ¥15 工价表引用工艺路线,应如何制作py和xml文件
  • ¥15 根据历史数据,推荐问题类型
  • ¥15 需要仿真图,简单的二阶系统实例
  • ¥15 stm32光控照明仿真
  • ¥15 使用人工智能的方法生成满足一定统计参数要求的随机数序列
  • ¥15 SENT协议中相关问题咨询