【发布时间】:2014-04-30 20:31:08
【问题描述】:
下面是一种算法尝试,可以在具有无权边的图中找到最短路径,并添加一个约束:一组不能在路径中的节点。因此,它不是找到节点之间的绝对最短路径,而是找到不包括某些节点的最短路径。
Wordnode是节点类,HashSet Avoids是必须避免的节点集合。算法中唯一发挥作用的地方是检查是否将节点添加到队列中。如果它在 avoids 中(或者如果它已经被访问过),不要添加它。我相信这个检查的效果应该等同于在 avoids 中暂时移除任何进出节点的边,尽管通过使用 HashSet 我避免了实际改变数据结构。
我认为算法是有效的,直到我设法通过向 avoids 添加单词来获得 更短的 路径。例如,如果 avoids 为空,那么对于 shortestPath(A, Z, {}) 它可能会返回 (A, B, E, C, F, L, D, Z),但是在将 E 和 C 添加到 avoids 并调用 shortestPath(A, Z, {E, C}) 后,我得到 (A, R, K, Z ), 更短...
我使用的图表有数千个节点,但我检查了 (A, B, E, C, F, L, D, Z) 和 (A, R, K, Z) 是有效路径。问题是当 avoids 为空时,当明显存在长度仅为 4 的路径时,该算法返回长度为 8 的路径。
这表明我的算法(如下)不正确,或者我的图形数据结构存在问题。后者会更难检查,所以我想我会先看看是否有人在下面发现问题。
那么,您能看出以下算法在 avoids 非空时比空时找到更短路径的任何原因吗?
注意:“this”是起点,目的地(“dest”)是一个参数。
谢谢
public LinkedList<String> shortestPath(Wordnode dest, int limit, HashSet<Wordnode> avoids)
{
HashSet<Wordnode> visited = new HashSet<>();
HashMap<Wordnode, Wordnode> previous = new HashMap<>();
LinkedList<Wordnode> q = new LinkedList<Wordnode>();
previous.put(this, null);
q.add(this);
Wordnode curr = null;
boolean found = false;
while(!q.isEmpty() && !found)
{
curr = q.removeLast();
visited.add(curr);
if(curr == dest)
found = true;
else
{
for(Wordnode n: curr.neighbors)
{
if(!visited.contains(n) && !avoids.contains(n))
{
q.addFirst(n);
previous.put(n, curr);
}
}
}
}
if(!found)
return null;
LinkedList<String> ret = new LinkedList<>();
while(curr != null)
{
ret.addFirst(curr.word);
curr = previous.get(curr);
}
return ret;
}
【问题讨论】:
-
BFS 不正确:您将顶点标记在错误的位置。推送到队列时要标记,否则同一个顶点会被处理多次。
标签: java algorithm graph breadth-first-search