POJ 2932 平面扫描
程序员文章站
2022-06-02 22:13:42
...
题意:
平面上有N个两两没有公共点的圆,i号圆的圆心在(xi,yi),半径为ri。求所有最外层的,即不包含于其他圆内部的圆。
分析:
在几何问题中,我们经常利用平面扫描技术来降低算法的复杂度。所谓平面扫描,是指扫描线在平面上按给定的轨迹移动的同时,不断根据扫描线扫过的部分更新信息,从而得到整体所要求得结果的方法。扫描的方法,既可以从左向右平移与y轴平行的直线,也可以固定射线的端点逆时针转动。
对于这道题,我们从左向右平移与y轴平行的直线的同时,维护与扫描线相交的最外层的圆的集合。从左向右移动的过程中,只有扫描线移动到圆的左右两端时,圆与扫描线的相交关系才会发生变化,因此我们先将所有的这样的x坐标枚举出来并排好序。
首先,我们来看一下扫描线移动到某个圆的左端时的情况。此时,我们需要判断该圆是否包含在其他圆中。为此,我们只需从当前与扫描线相交的最外层的圆中,找到上下两侧y坐标方向距离最近的两个圆,并检查他们就足够了。这是因为,假设该圆被包含于更远的圆中,却不被包含于最近的圆中,就会如下图所示,得出两圆相交的结论。而这与题目所给的条件不符。于是,只要用二叉查找树来维护这些圆,就能够在O(logn)时间内取得待检查的圆了。
其次,我们看一下扫描线移动到某个圆的右端时的情形。此时的处理很简单,如果该圆已经包含于其他圆中就什么也不做,如果是最外层的圆就将它从二叉树中删去。综上,总的复杂度为O(nlogn)。
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 40000 + 10;
int n;
double x[maxn], y[maxn], r[maxn];
//判断圆i是否在圆j的内部
bool inside(int i, int j)
{
double dx = x[i] - x[j];
double dy = y[i] - y[j];
return dx * dx + dy * dy <= r[j] * r[j];
}
void solve()
{
//枚举关键点
vector<pair<double, int> > events; //圆的左右两端的x坐标
for (int i = 0; i < n; i++){
events.push_back(make_pair(x[i] - r[i], i)); //圆的左端
events.push_back(make_pair(x[i] + r[i], i + n)); //圆的右端
}
sort(events.begin(), events.end());
//平面扫描
set<pair<double, int> > outers; //与扫描线相交的最外层的圆的集合
vector<int> res; //最外层圆的列表
for (int i = 0; i < events.size(); i++){
int id = events[i].second % n;
if (events[i].second < n){ //扫描到左端
set<pair<double, int> > :: iterator it = outers.lower_bound(make_pair(y[id], id));
if (it != outers.end() && inside(id, it -> second))
continue;
if (it != outers.begin() && inside(id, (--it) -> second))
continue;
res.push_back(id);
outers.insert(make_pair(y[id], id));
}
else{ //扫描到右端
outers.erase(make_pair(y[id], id));
}
}
sort(res.begin(), res.end());
printf("%d\n", res.size());
for (int i = 0; i < res.size(); i++){
printf("%d%c", res[i] + 1, i + 1 == res.size() ? '\n' : ' ');
}
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++){
scanf("%lf%lf%lf", &r[i], &x[i], &y[i]);
}
solve();
return 0;
}
转自:https://blog.csdn.net/a2459956664/article/details/51416881
参考资料:程序挑战
推荐阅读
-
【石门】【线段树】【扫描线】POJ2482 Stars in your Windows
-
Stars in Your Windows POJ2482(线段数组扫描线、区间最大、区间更新)
-
[poj1151]Atlantis矩形面积求交(扫描线+线段树)
-
poj1151 Atlantis(线段树+扫描线)
-
POJ 1151 Atlantis (扫描线+线段树)
-
poj1151(线段树+扫描线)
-
Atlantis POJ1151(线段树扫描线)
-
POJ 1177 Picture 【线段树】【矩形周长并(横纵扫描线、离散化)】
-
POJ - 1151(线段树+扫描线)
-
POJ2932Coneology(计算几何、平面扫描)