【发布时间】:2019-05-01 01:53:44
【问题描述】:
我正在尝试遵循 Dijkstra 算法的伪代码,但我不明白它如何为我提供最短路径。按照这个伪代码:
DijkstrasAlgorithm(G, w, s)
InitalizeSingleSource(G, s)
S = 0
Q = G.V
while Q != 0
u = ExtractMin(Q)
S = S∪{u}
for each vertex v ∈ G.Adj[u]
Relax(u, v, w)
这是我最终得到的代码:
DijkstrasAlgorithm(string w, string s) {
string u;
string s;
InitalizeSingleSource(s);
for (map<string, Vertex*>::iterator it = vertices.begin();
it!=vertices.end(); ++it) {
minQ.insert(it->first, it->second->key);
}
while (u != "empty") {
u = minQ.extractMin();
if (!s.empty()) {
s.append("->");
}
s.append(u);
vector<Neighbor*>::iterator it = adjList[u].begin();
while (it != adjList[u].end()) {
relax(u, w, (*it)->weight);
it++;
}
}
return s;
}
问题是,这段代码没有给我最短路径。看着伪代码,我不明白它会如何。如果我有 5 个顶点(a、b、c、d 和 e),假设我想找到从 a 到 c 的最短路径,而这条最短路径是 a->b->c。所有这些代码都会给我是 c->e->d->b->a。
我只是不明白这里的逻辑。我们使用 InitalizeSingleSource(s) 将顶点的所有键值初始化为 INT_MAX,除了 s 为 0。从这里我们找到顶点键值的最小值,而不是使用 adjList。
我们不会在到达路径尽头时停止,而是在 minQ 为空时停止。所有这一切都是打印所有顶点而不是最短路径。最重要的是,我们将大部分键设置为 INT_MAX,因此找到它们之间的最小值感觉都是多余的。
完成后,我们使用 G.E/G.Adj[u] 进行松弛函数,即使我们没有在测量最小路径时使用边缘。
有很多东西对我来说没有意义,但我想最奇怪的部分是根据顶点 (G.V) 而不是边 (G.E) 设置 Q/minQ。这应该如何找到最小路径?谁能解释我不理解算法伪代码的哪一部分?谢谢!
编辑:也包括“放松”功能。
relax(string u, string v, int weight) {
if (vertices[v]->key > (vertices[u]->key + weight)) {
vertices[v]->key = (vertices[u]->key + weight);
vertices[v]->pi = new std::string(u);
}
}
【问题讨论】:
-
建议——除非你完全理解算法,否则不要浪费时间编写程序。花点时间手工浏览算法,然后编写程序。
-
有一系列非常棒的教程将引导您完成广度优先、贪心广度优先、dijkstra、A* 等。
-
我现在正在尝试学习教程,但它是伪代码,并且伪代码似乎没有执行教程所说的操作,这是我目前困惑的根源。
-
当我第一次了解 Dijkstra 的算法时,我发现使用基于 2D 网格的图(而不是任意的非网格图)最容易理解。 Amit's A* tutorials 是我遇到过的最好的。我强烈推荐他们。如果您担心 A* 与(纯)Dijkstra's:A* 与 Dijkstra's 完全相同,除了它在路径成本中引入了启发式。如果您在 A* 中将启发式设置为 0,您将拥有普通的 Dijkstra。
-
这是一个众所周知的算法,所以很多算法书都会解释它,你的老师可能会这样做,应该很容易在网上找到很多信息。使用笔和纸也可以帮助理解算法以及使用调试器。
标签: c++ data-structures dijkstra