仅返回实际最短路径中的顶点

发布于 2024-10-26 20:00:54 字数 1437 浏览 3 评论 0原文

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

我想做的事情:

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

注意:使用广度优先搜索,不是迪杰斯特拉的。

我所拥有的:

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

我很难区分最短路径中的顶点和仅通过算法运行但不是最短路径中的顶点。

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

我还没有找到任何提出同样问题的线程,也没有找到任何包含此问题的 BFS 演练,所以我不确定我是否让这个问题变得更加困难比它是什么?

编辑:为那些可能感兴趣的人提供代码(完全不确定我是否在避免圆圈?)

编辑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 邻居的普通迭代器

感谢阅读!

I know the title is a bit messy, but I don't know how to explain it better.

What I'm trying to do:

Using a graph found in a text file, find and print the shortest path (minimum amount of vertices) from vertex A to vertex B.

Note: using breadth-first search, not Dijkstra's.

What I've got:

A working algorithm that applies BFS on the graph, but no good way of actually printing out the shortest path.

I'm having a hard time distinguishing a vertex in the shortest path from one that is simply run through the algorithm, but not in the shortest path.

For example: Find the shortest path between 0 and 4.
0 connects to 1,2 and 3. 1 connects to 4.
My path turns out to be [0,1,2,3,4] instead of [0,1,4].

I haven't been able to find any threads asking the same question, or any walk-through of BFS that includes this, so I'm not sure if I'm making this out to be way harder than it is?

Edit: code for those who may be interested (not sure at all if I'm avoiding circles?)

Edit 2: Changed the way I store my path to a Stack.

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());
        }
    }
}

Some explanation of variables and methods:

v = vertex of origin

w = target vertex

g = graph

vi = a normal iterator that iterates over the neighbours of v

Thanks for reading!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心不设防 2024-11-02 20:00:54

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

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;
}

You will have to have specific path field for each vertex. That way you can keep track of the paths you've chosen, hence the short path found. I will use an String array, just like you used the Boolean array for storing visited vertices.

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;
}
墨小沫ゞ 2024-11-02 20:00:54

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

步骤 1:初始化访问列表,使每个元素都是 '-1',或“未访问”

步骤 2:将第一个节点标记为自身已访问 visited[v] = v;< /code>

执行 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,最后以相反的顺序打印它们。 (这是使用堆栈或递归打印方法完成的。)

希望这是有道理的。 :)

Another compact (space-wise) solution that us assistants have suggested and doesn't use O(n^2) storage space is to have each node store only which node it came from. This can be done by changing the visited-list to an integer array (int[] visited).

step 1: initialize visited list, so that every element is '-1', or "unvisited"

step 2: mark the first node as visited by itself visited[v] = v;

Do a BFS (like you do, with the following modifications:)

when moving from v -> v_next:

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

This way, if w is reachable, visited[w] will store which node it came from, from that node, you can backtrack all the way back to v and finally print them in the opposite order. (This is done either using a stack or a recursive print method.)

Hope that makes sense. :)

才能让你更想念 2024-11-02 20:00:54

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

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

When you store a vertex in the BFS queue, you also need to store a copy of the path through which it has been reached, so that it will be available once that vertex is dequeued. As it is now, your code does not keep any kind of path information on the queued vertices - it only keeps a list of the nodes it visits.

You could, for example, use a separate queue that will be processed in parallel, in which you will store the current path, and then restore it once you dequeue the next vertex to search.

时间你老了 2024-11-02 20:00:54

您需要将当前节点推入堆栈,并且仅在到达目的地后打印整个堆栈。

You need to push your current node onto a stack, and only print the whole stack out once you reach the destination.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文