我必须得到一个算法,它找到地球上最近的两个点。我编写了下面的代码,它适用于我的测试,但执行时间太长。我试图修改代码,但它没有帮助。也许有人会知道我该怎么做?
struct Points
{
std::string key;
double latitude;
char latSign;
double longitude;
char longSign;
};
typedef std::pair<std::pair<std::string, std::string>, double> myType;
double toFraction(short deegres, short minutes)
{
return (double)deegres + (minutes / 60.0);
}
double orthodroma(const Points &a, const Points &b)
{
double radian = M_PI / 180;
return acos((cos((90 - a.latitude) * radian) *
cos((90 - b.latitude) * radian)) +
(sin((90 - a.latitude) * radian) *
sin((90 - b.latitude) * radian) *
cos((a.longitude - b.longitude) * radian))) *
(180 / M_PI);
}
bool sortByLatitude(const Points &a, const Points &b)
{
return a.latitude > b.latitude;
}
myType bruteForce(const std::vector<Points> &vec, int begin, int n)
{
myType result;
double min = 1000000;
int _i, _j;
if(n > 300)
{
}
for(int i = begin; i < (n + begin) - 1; i++)
{
for(int j = i + 1; j < n + begin; j++)
{
double tmp;
tmp = orthodroma(vec[i], vec[j]);
if(tmp < min)
{
min = tmp;
_i = i;
_j = j;
}
}
}
result.first.first = vec[_i].key;
result.first.second = vec[_j].key;
result.second = min;
return result;
}
myType divideAndConquer(std::vector<Points> &vec, int begin, int n)
{
if(n <= 3)
{
return bruteForce(vec, begin, n);
}
std::sort(vec.begin(), vec.end(), sortByLatitude);
int middle = n / 2;
Points point = vec[middle];
myType left = divideAndConquer(vec, begin, middle);
myType right = divideAndConquer(vec, middle, (n - middle));
bool which;
double minDist = std::min(left.second, right.second);
if(left.second < right.second)
which = false;
else
which = true;
std::vector<Points> arr;
for(int i = 0; i < n; i++)
{
if(abs(vec[i].latitude - point.latitude) < minDist)
{
arr.push_back(vec[i]);
}
}
int size = arr.size();
if(size < 2)
{
if(which)
return right;
else
return left;
}
else
{
myType one = bruteForce(arr, 0, size);
if(which)
{
if(one.second < right.second)
return one;
else
return right;
}
else
{
if(one.second < left.second)
return one;
else
return left;
}
}
}
PS。我必须使用分治法。
答案 0 :(得分:0)
一些可能会稍微改善性能的想法:
只对数组进行一次排序(在第一次递归调用分治法之前)。
将点添加到arr
向量中时,您可以从中间位置开始,先向前移动,然后向后移动。优点是,只要一个点离中间点足够远,就可以打破每个循环。由于数组按纬度排序,因此可以保证其余的点都在所需的范围之外。
您可以将另一个参数传递给divideAndConquer方法,表示到目前为止已知的最小距离。这可以导致更小的arr
数组,更快地处理。目前,可能是左子阵列的距离非常小。但是,在求解正确的子数组时,递归调用当前没有关于已找到的小距离的信息。
答案 1 :(得分:0)