线段相交问题-线段扫描法-set模拟二叉树

版权声明:看我干嘛? 你又没打算转载我的博客~ https://blog.csdn.net/wjh2622075127/article/details/82901532

线段相交问题: 线段扫描法

预处理:

对每个线段, 解析其端点信息.

线段分两类, 一类与x轴平行, 作为扫描线段, 左端点记为LEFT, 右端点记为RIGHT

第二类与y轴平行, 作为区间查询线段, 上端点记为TOP, 下端点记为BOTTOM

对每个端点, 其类型为EndPoint, 除了存储坐标外, 还存储其线段下标以及端点类型


核心步骤:

给线段的端点排序, 按坐标y从小到大的顺序, 如果相同, 则按照标记从小到大(bottom, left, right, top依次递增)

维护一个set集合, 记录那些与y轴平行的线段的底端点的x坐标(每遇到就插入). 当遇到这些线段的顶端点时, 将该坐标弹出.

遇到一个与x轴平行线段的左端点时, 进行线段扫描. 右端点不进行处理

在set集合中的这些端点代表着当前y区间长度可访问到的与y轴平行的线段, 但扫描线段要与它们相交, 还需要判断区间长度, 用set内置函数可解决.


代码:

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

class Point {
public:
	Point(int x = 0, int y = 0): x(x), y(y) {}
	int x, y;
};

class Segment {
public:
	Segment() {}
	Segment(Point p1, Point p2): p1(p1), p2(p2) {}
	Point p1, p2;
};

class EndPoint {
public:
	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;
		} else return p.y < ep.p.y;
	}
};

EndPoint EP[2 * 1000000];
#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3

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;
	int cnt = 0;
	BT.insert(1000000001);
	
	for (int i = 0; i < 2 * n; ++i) {
		if (EP[i].st == TOP) {
			BT.erase(EP[i].p.x);
		} else if (EP[i].st == LEFT) {
			set<int>::iterator start = BT.lower_bound(S[EP[i].seg].p1.x);
			set<int>::iterator end = BT.upper_bound(S[EP[i].seg].p2.x);
			cnt += distance(start, end);
		} else if (EP[i].st == BOTTOM) {
			BT.insert(EP[i].p.x);
		}
	}
	return cnt;
}

int main()
{
	int n;
	cin >> n;
	vector<Segment> seg;
	for (int i = 0; i < n; ++i) {
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		seg.push_back(Segment(Point(x1, y1), Point(x2, y2)));
	}
	int ans = manhattanIntersection(seg);
	cout << "这些线段共有 " << ans << " 个交点." << endl;
}
/*
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
*/

猜你喜欢

转载自blog.csdn.net/wjh2622075127/article/details/82901532