【问题标题】:Returning only the vertices in the actual shortest path仅返回实际最短路径中的顶点
【发布时间】:2011-03-31 23:20:10
【问题描述】:

我知道标题有点乱,但我不知道如何更好地解释它。

我想做的事:

使用在文本文件中找到的图,找到并打印从顶点 A 到顶点 B 的最短路径(最少顶点数)。

注意:使用广度优先搜索,而不是 Dijkstra 的。

我有什么:

一种在图上应用 BFS 的有效算法,但没有实际打印出最短路径的好方法。

我很难将最短路径中的顶点与仅通过算法运行但不在最短路径中的顶点区分开来。

例如:找到 0 到 4 之间的最短路径。 0 连接到 1,2 和 3。1 连接到 4。 我的路径原来是 [0,1,2,3,4] 而不是 [0,1,4]。

我无法找到任何询问相同问题的线程,或任何包含此问题的 BFS 演练,所以我不确定我是否会这样做方式 em> 比现在更难?

编辑:代码供可能感兴趣的人使用(完全不确定我是否要避开圈子?)

编辑 2:改变了我将路径存储到堆栈的方式。

public String findPath(int v, int w) {
    Queue<Integer> q = new LinkedList<Integer>();
    boolean[] visited = new boolean[g.numVertices()];

    q.add(v);
    Stack<Integer> path = new Stack<Integer>();
    while(q.peek() != null) {
        runBFS(q.poll(),w,visited,q,path);
    }
    return path.toString();
} 

private void runBFS(int v, int w, boolean[] visited, Queue<Integer> q, Stack<Integer> path) {
    if(visited[v]) {
    }
    else if(v == w) {
        path.add(v);
        q.clear();
    }
    else {
        path.add(v);
        visited[v] = true;
        VertexIterator vi = g.adjacentVertices(v);
        while(vi.hasNext()) {
                q.add(vi.next());
        }
    }
}

变量和方法的一些解释:

v = 原点

w = 目标顶点

g = 图

vi = 遍历 v 的邻居的普通迭代器

感谢阅读!

【问题讨论】:

  • 你好,能不能发个源代码。
  • 您的图形在代码中是如何表示的?你如何避免圈子?有很多这样的问题最好通过发布一些代码来回答......
  • 我添加了一些代码。如果有关于图表的任何缺失信息,请告诉我。
  • 我想我在这里遗漏了一些东西。一方面,Java 中的 String 对象不是不可变的吗?将path 更改为runBFS 有什么好处?
  • 你说得对,我的错。但是,我现在已将其从 String 更改为 Stack,并将在代码中进行适当的更改。

标签: java shortest-path breadth-first-search graph-traversal


【解决方案1】:

您必须为每个顶点设置特定的路径字段。这样您就可以跟踪您选择的路径,从而找到短路径。我将使用一个字符串数组,就像您使用布尔数组来存储访问的顶点一样。

public String findPath(int v, int w) {
    Queue<Integer> q = new LinkedList<Integer>();
    boolean[] visited = new boolean[g.numVertices()];
    String[] pathTo = new String[g.numVertices()];

    q.add(v);
    pathTo[v] = v+" ";
    while(q.peek() != null) {
        if(runBFS(q.poll(),w,visited,q,pathTo))
        break;
    }
    return pathTo[w];
}

private boolean runBFS(int v, int w, boolean[] visited, Queue<Integer> q, String[] pathTo) {
    if(visited[v]) {
    }
    else if(v == w)
        return true; 
    }
    else {
        visited[v] = true;
        VertexIterator vi = g.adjacentVertices(v);
        while(vi.hasNext()) {
            int nextVertex = vi.next();
            pathTo[nextVertex] = pathTo[v] + nextVertex + " ";
            q.add(nextVertex);
        }
    }
    return false;
}

【讨论】:

  • 正是我需要的,非常感谢!很好的解决方案,我认为我的问题是我只对从 X 到 Y 的路径感兴趣,没有别的。
  • 太棒了!正是我想要的。
【解决方案2】:

我们的助手建议的另一个紧凑(空间方面)解决方案不使用 O(n^2) 存储空间是让每个节点只存储它来自哪个节点。这可以通过将访问列表更改为整数数组 (int[] visited) 来完成。

第一步:初始化访问列表,让每个元素都是'-1',或者“未访问”

第二步:将第一个节点标记为自己访问过visited[v] = v;

做一个 BFS(和你一样,做以下修改:)

当从 v 移动时 -> v_next:

if(visited[v_next] == -1)
{
  visited[v_next] = v;
  q.put(v_next);
}
// else skip it, it's already been visited

这样,如果 w 可达,visited[w] 将存储它来自哪个节点,从那个节点,你可以一直回溯到 v,最后以相反的顺序打印它们。 (这可以使用堆栈或递归打印方法完成。)

希望这是有道理的。 :)

【讨论】:

    【解决方案3】:

    当您将顶点存储在 BFS 队列中时,您还需要存储到达该顶点的路径的副本,以便在该顶点出列时可用。就像现在一样,您的代码不会在排队的顶点上保留任何类型的路径信息 - 它只保留它访问的节点的列表。

    例如,您可以使用将并行处理的单独队列,在其中存储当前路径,然后在将下一个要搜索的顶点出队后恢复它。

    【讨论】:

    • 这个有用的解释很有帮助。见here我的实现
    【解决方案4】:

    您需要将当前节点推送到堆栈上,并且只有在到达目的地后才将整个堆栈打印出来。

    【讨论】:

    • 返回的结果和我之前的方法一模一样,能不能详细点?
    • 备份时是否将其弹出?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多