【发布时间】:2015-02-26 05:59:44
【问题描述】:
用于最近对的标准扫描线算法是众所周知的,如 here 所述,它使用扫描线水平扫描点集,仅保留当前点当前最佳距离内的点。
通常,点最初必须按 x 坐标排序,而边界框(在 c++ 实现的情况下为 std::set)必须按 y 坐标排序,如this c++ implementation 所示。
但是,在尝试实现时,我不小心忘记按 x 坐标对点进行排序,而是按 y 坐标对它们进行排序。令人惊讶的是,这似乎仍然有效。 你可以看到我的实现here,它基本上遵循标准线扫描最接近对算法的略微修改版本:
#include <iostream>
#include <set>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
#define x second
#define y first
typedef pair<long long, long long> pll;
inline double dist(pll p1, pll p2)
{
return sqrt((double) (p2.y - p1.y)*(p2.y - p1.y) + (p2.x - p1.x)*(p2.x - p1.x));
}
int main(int argc, const char * argv[])
{
int numPoints;
cin >> numPoints;
vector <pll> points;
points.resize(numPoints);
for (int i = 0; i < numPoints; i++)
{
cin >> points[i].x >> points[i].y;
}
//Sorts the points by y coordinate (because y is first)
sort(points.begin(), points.end());
double shortestDistSoFar = INFINITY;
set <pll> boundingBox; //Bounding box maintained by y-coordinate
boundingBox.insert(points[0]);
int left = 0;
pll best1, best2;
for (int i = 1; i < numPoints; i++)
{
//Maintain only points to the left of the current point whose distance is less than bestDist
while ((left < i) && (points[i].x - points[left].x > shortestDistSoFar))
{
boundingBox.erase(points[left]);
left++;
}
//Consider only points within bestDist of the current point
for (auto it = boundingBox.lower_bound(pll(points[i].y - shortestDistSoFar, points[i].x - shortestDistSoFar));
it != boundingBox.end() && it->y <= points[i].y + shortestDistSoFar; it++)
{
if (dist(*it, points[i]) < shortestDistSoFar)
{
shortestDistSoFar = dist(*it, points[i]);
best1 = *it;
best2 = points[i];
}
}
boundingBox.insert(points[i]);
}
return 0;
}
按照 y 坐标递增的顺序访问每个点,并为每个点检查从 y-bestDist 到 y+bestDist 的所有点,当找到新的最短距离时更新 bestDist 并从集合中删除其 x 坐标距离当前点大于 bestDist。
这个修改后的算法还能用吗(我只测试了几个案例),运行时间还是O(N lgN)吗?
【问题讨论】:
-
从你的距离函数中删除 sqrt,它是不必要且昂贵的
标签: c++ algorithm computational-geometry