太慢的最短路径算法[关闭]
Posted
技术标签:
【中文标题】太慢的最短路径算法[关闭]【英文标题】:Too slow shortest path algorithm [closed] 【发布时间】:2014-02-10 18:00:57 【问题描述】:我正在用最短路径算法解决一个问题,但它太慢了,问题是我有 N 个点,只有当它们之间的距离小于或等于 D 时,这些点才能连接,我有起始索引和完成(代码中的“ciel”)索引并且必须以双格式返回最短路径。一开始我以为sqrt太慢了,但是当我改变它时,它仍然太慢了。我正在回溯距离并在那里使用 sqrt 以获得更好的速度,但它太慢了。我使用了优先队列。有关更多信息,输入包括点的 X 和 Y、生成边缘的 D 最大距离、开始索引和结束索引。最多可以有 1000 个点。
这是我的代码http://pastebin.com/pQS29Vw9 请问有什么方法可以让它更快吗?
#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <utility>
using namespace std;
const int MAX = 1001;
const int INF = 1e9;
std::vector< std::pair<int, int> > edges[MAX]; // hrany a vzdialenosti medzi bodmi a hranami
int N; // pocet vrcholov
int start, ciel; // start a ciel index
double dijkstra()
int vis[N]; // pocet navstiveni daneho bodu
int prevNodes[N][2];
for(int i=0;i < N;i++)
prevNodes[i][1] = INF;
std::priority_queue< std::pair<int, int> > heap; // halda
for(int i = 0; i < N; i++) vis[i] = 0;
heap.push(pair<int, int>(0, start));
while(!heap.empty())
pair<int, int> min = heap.top(); // vybratie dalsieho
heap.pop(); // vyhodenie pozreteho
min.first *= -1.0; // kvoli spravnemu fungovaniu priority
int v = min.second; // len pre oko
vis[v]++;
if (v == ciel && vis[v] == 1)
double d = 0.0;
int prevIndex = ciel, nextIndex = prevNodes[ciel][0];
while(1)
for(int j=0;j < edges[nextIndex].size();j++)
if(edges[nextIndex][j].first == prevIndex)
d += sqrt(double( edges[nextIndex][j].second ));
break;
prevIndex = nextIndex; // posunutie
if(nextIndex == start) // ak sme uz na zaciatku
break;
else
nextIndex = prevNodes[nextIndex][0];// posun dalej
return d; // najkratsia cesta
for (int i = 0; i < (int) edges[v].size(); i++)
if (vis[edges[v][i].first] < 1)
if(prevNodes[edges[v][i].first][1] > min.first + edges[v][i].second)
prevNodes[edges[v][i].first][0] = min.second;
prevNodes[edges[v][i].first][1] = min.first + edges[v][i].second;
heap.push(pair<int, int>(-(min.first + edges[v][i].second), edges[v][i].first));
return -1;
int main()
int X;
scanf("%d",&X);
double answers[X];
for(int i=0;i < X;i++)
int D, sIndex, eIndex; // N je globalne
scanf("%d %d", &N, &D); // N
int DD = D * D;
for(int j=0;j < N;j++)
edges[j].clear();
int V[N][2]; // N
int x, y;
for(int k=0;k < N;k++) // N
scanf("%d %d", &x, &y);
V[k][0] = x;
V[k][1] = y;
for(int a=0;a < N;a++)
for(int b=0;b < N;b++)
int v = (((V[a][0] - V[b][0]) * (V[a][0] - V[b][0]) +
(V[a][1] - V[b][1]) * (V[a][1] - V[b][1])));
if(v > DD)
continue;
else
edges[a].push_back(pair<int, int>(b, v));
edges[b].push_back(pair<int, int>(a, v));
scanf("%d %d", &start, &ciel);
start--;
ciel--;
double dijLen = dijkstra();
if(dijLen < 0)
answers[i] = -1;
else
answers[i] = dijLen;
for(int i=0;i < X;i++)
if(answers[i] < 0)
printf("Plan B\n");
else
printf("%.2f\n", answers[i]);
return 0;
【问题讨论】:
CodeReviewsqrt
是一个常数函数,随着 N 的增长,它在很大程度上与算法的性能无关。各种 N 的执行时间的图表是什么样的?是否符合预期范围?
我找不到边界,所以我根本无法检查任何东西。
@user1295618 好吧,看看性能图表 - 它看起来是否以有利的方式扩展?也就是说,对于 N=10、N=100、N=1000,它是如何运行的?他们都“太慢”了吗? N越大,它会变得太慢吗?如果有,是由什么因素决定的?它是一个恒定的(只是需要更快的挂钟)因素吗?
交叉发布:codereview.stackexchange.com/questions/41351
【参考方案1】:
需要考虑的三种可能的算法改进:
改进搜索
Djikstra 的算法将探索起始节点 S 内的所有点,其中 S 是起点和终点之间的最短距离。
如果您使用A* search(例如,使用与目标的欧几里得距离的启发式算法),那么您应该会发现需要探索的点要少得多。
改进边缘构造
根据点的分布方式,您可能会发现最好通过以下方式找到距离 D 内的边:
-
想象一个边长为 D 的网格覆盖在平面上
将每个点添加到与它所属的方格相对应的桶中
当您需要找到一个点的邻居时,您只需要测试相邻桶中的点,而不是每个点。
预处理的改进
根据点的分布,您可能会发现仅在到达顶点时构造有效边比预先计算所有边更有效。
如果起点和终点很近,这可能会节省大量时间。
【讨论】:
我根据 codereview 中交叉问题的提示修改了代码,所以现在我正在检查 dijkstra 中的边缘,并且点按 X 坐标排序,因此如果两个点是,我可以结束循环 > D 远。这是代码pastebin.com/0WiuVCNM 但是,测试人员说它给出了错误的答案,但是在两个测试输入上它运行良好,所以你能检查代码的逻辑吗? @user1295618 尝试将 sqrt 移回 dist 函数。目前,您正在根据距离的平方计算最短路径,这可能并不总是给出相同的答案。 我尝试了 A* 方式,因为它由于堆溢出而崩溃。这是pastebin.com/sNf1w55c,我正在等待法官的回复,因为它无法在他们的编译器上编译。 我修好了,但现在我又得到了错误的答案,请问有人可以检查代码逻辑吗?以上是关于太慢的最短路径算法[关闭]的主要内容,如果未能解决你的问题,请参考以下文章
数据结构与算法图最短路径算法 ( Floyed 算法 | 图最短路径算法使用场景 | 求解图中任意两个点之间的最短路径 | 邻接矩阵存储图数据 | 弗洛伊德算法总结 )