【问题标题】:Finding the shortest path between two points(bfs)寻找两点之间的最短路径(bfs)
【发布时间】:2018-09-18 22:14:18
【问题描述】:

我有一个任务。我需要找到两点之间的最短路径。为此,我使用广度优先搜索算法。我创建了类Graph,它具有顶点数量和邻接列表。这是我的代码:

class Graph
{
    private int V;   
    private LinkedList<Integer> adj[]; //Adjacency Lists

    // Constructor
    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }

    // Function to add an edge into the graph
    void addEdge(int v,int w)
    {
        adj[v].add(w);
    }

    // prints BFS traversal from a given source s
    void BFS(int s)
    {
        // Mark all the vertices as not visited(By default
        // set as false)
        boolean visited[] = new boolean[V];

        // Create a queue for BFS
        LinkedList<Integer> queue = new LinkedList<Integer>();

        // Mark the current node as visited and enqueue it
        visited[s]=true;
        queue.add(s);

        while (queue.size() != 0)
        {
            // Dequeue a vertex from queue and print it
            s = queue.poll();
            System.out.print(s+" ");

            // Get all adjacent vertices of the dequeued vertex s
            // If a adjacent has not been visited, then mark it
            // visited and enqueue it
            Iterator<Integer> i = adj[s].listIterator();
            while (i.hasNext())
            {
                int n = i.next();
                if (!visited[n])
                {
                    visited[n] = true;
                    queue.add(n);
                }
            }
        }
    }

    // Driver method to
    public static void main(String args[])
    {
       Graph g = new Graph(8);
        g.addEdge(0, 5);
        g.addEdge(0, 7);
        g.addEdge(1, 5);
        g.addEdge(1, 4);
        g.addEdge(1, 2);
        g.addEdge(2, 1);
        g.addEdge(2, 4);
        g.addEdge(2, 3);
        g.addEdge(3, 4);
        g.addEdge(3, 2);
        g.addEdge(4, 5);
        g.addEdge(4, 1);
        g.addEdge(4, 2);
        g.addEdge(4, 3);
        g.addEdge(5, 0);
        g.addEdge(5, 1);
        g.addEdge(5, 4);
        g.addEdge(6, 7);
        g.addEdge(7,6);
        g.addEdge(7,0);
        g.BFS(2);

        g.BFS(2);
    }
}

但我需要打印从开始索引到结束的最短路径的函数。我该如何组织它。请帮我。

【问题讨论】:

  • 不要重新发明轮子,使用JGraphT
  • 感谢您的帮助,但我无法使用库
  • 为什么不能使用库?
  • 这是一项奥林匹克任务
  • 如果是奥林匹克任务,你不应该自己做吗?

标签: java algorithm


【解决方案1】:

我使用了递归,所有答案都将存储在 arrayList 中。

getPath(int from, int to, int current, String answer)

  • 从 - 一个起点
  • 到-结束点
  • current - 只是一个当前值
  • 答案 - 整个路径

只需将此代码添加到 Graph 类。

public ArrayList<String> answers = new ArrayList<String>();

public void printShortAnswer() {
    String realAnswer = "";
    for (String answer : answers) {
        if (realAnswer == "" || realAnswer.length() > answer.length()) {
            realAnswer = answer;
        }
    }
    System.err.println("The shortest path is: " + realAnswer);
}

//store all answers in answers
public boolean getPath(int from, int to, int current, String answer) {
    boolean visited[] = new boolean[V];
    visited[from] = true;
    visited[current] = true;

    if (current == to) {
         answers.add(answer);
        return true;
    }

    Iterator<Integer> i = adj[current].listIterator();
    while (i.hasNext())
    {
        int n = i.next();
        if (!visited[n])
        {
            visited[n] = true;
            getPath(from, to, n, answer + " " + n);
        }
    }
    return false;
}

要运行它,只需使用此设置

  Graph g = new Graph(12);
    g.addEdge(0, 1);
    g.addEdge(0, 2);

    //set 1
    g.addEdge(1, 3);
    g.addEdge(3, 4);
    g.addEdge(4, 5);

    //set 2
    g.addEdge(2, 8);
    g.addEdge(8, 9);
    g.addEdge(9, 11);
    g.addEdge(11, 5);

    g.addEdge(0, 5);
    //g.BFS(0);

    int startPoint = 0;
    g.getPath(startPoint, 5, startPoint, startPoint + " ");
    g.printShortAnswer();

别忘了导入 ArrayList。

import java.util.ArrayList;

输出将是:

  • 0 1 3 4 5
  • 0 2 8 9 11 5
  • 0 5
  • 最短路径为:0 5

【讨论】:

  • 运行这段代码时,别忘了清除访问过的数组。如果你运行 BFS,那么 getPath。
  • 非常感谢您的回答,但我得到了 java.lang.StackOverflowError
  • 在 java.util.LinkedList.listIterator(LinkedList.java:868) 处的 java.util.AbstractList.listIterator(AbstractList.java:299) 处的线程“主”java.lang.StackOverflowError 异常com.company.Graph.getPath(Graph.java:62) at com.company.Graph.getPath(Graph.java:69) at com.company.Graph.getPath(Graph.java:69) at com.company.Graph .getPath(Graph.java:69) 在 com.company.Graph.getPath(Graph.java:69) 在 com.company.Graph.getPath(Graph.java:69) 在 com.company.Graph.getPath(Graph. java:69)
  • 告诉我,你使用了哪些值?用于设置图表。当您创建图表时 -> Graph g = new Graph(12);.. 等等。另外,您的起点和终点
  • 好的,我发现访问点有问题。如果您有无限循环,则代码将失败。 0 到 5,5 到 0
【解决方案2】:

广度优先搜索在这里是合适的,因为当你第一次访问目标节点时,你会通过最短路径进行。这是可行的,因为所有边都具有相同的权重,即 1。如果边可以具有不同的权重,则边数最少的路径不一定是最短路径,您将需要其他算法,例如 Dijkstra's

您的代码不会检查您是否已到达目的地;它只是以广度优先顺序访问所有节点。

你也不能边走边打印节点,因为当你访问一个相邻的未访问节点时,你还不知道它是否是最短路径的一部分,或者你是否走错了方向。

对此的解决方案是为每个顶点存储前一个顶点,即您来自的那个顶点。例如,如果您从顶点 0 开始搜索,您将访问相邻的顶点 5 和 7。因此,5 和 7 的前一个顶点都是 0。

此信息可以起到双重作用:如果您使用 -1 表示“没有顶点”,则之前的 -1 顶点表示尚未访问该顶点。

当您访问目的地时,只需通过先前节点的信息回溯您的步骤,直到您到达原始顶点。此列表将是从目的地到起点的路径。

这是(我可怜的)Java 中的实现:

import java.util.LinkedList;
import java.util.Iterator;

class Graph
{
    private int V;   
    private LinkedList<Integer> adj[];

    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];

        for (int i = 0; i < v; i++) {
            adj[i] = new LinkedList();
        }
    }

    void addEdge(int v, int w)
    {
        adj[v].add(w);
    }

    LinkedList shortest(int from, int to)
    {
        LinkedList<Integer> queue = new LinkedList<Integer>();
        LinkedList<Integer> res = new LinkedList<Integer>();

        int prev[] = new int[V];

        if (from == to) return res;
        queue.add(from);

        for (int i = 0; i < V; i++) {
            prev[i] = -1;
        }        

        while (queue.size() != 0) {
            int curr = queue.poll();
            Iterator<Integer> i = adj[curr].listIterator();

            while (i.hasNext()) {
                int n = i.next();

                if (prev[n] == -1) {                // unvisited?
                    prev[n] = curr;                 // store previous vertex

                    if (n == to) {                  // we're finally there!
                        while (n != from) {         // build result list ...
                            res.addFirst(n);
                            n = prev[n];
                        }

                        return res;                 // ... and return it
                    }                    

                    queue.add(n);
                }
            }
        }

        return res;
    }

    public static void main(String args[])
    {
        Graph g = new Graph(9);

        g.addEdge(0, 5);
        g.addEdge(0, 7);
        g.addEdge(1, 5);
        g.addEdge(1, 4);
        g.addEdge(1, 2);
        g.addEdge(2, 1);
        g.addEdge(2, 4);
        g.addEdge(2, 3);
        g.addEdge(3, 4);
        g.addEdge(3, 2);
        g.addEdge(4, 5);
        g.addEdge(4, 1);
        g.addEdge(4, 2);
        g.addEdge(4, 3);
        g.addEdge(5, 0);
        g.addEdge(5, 1);
        g.addEdge(5, 4);
        g.addEdge(6, 7);
        g.addEdge(7,6);
        g.addEdge(7,0);

        for (int a = 0; a < 9; a++) {
            System.out.print("--- ");
            System.out.println(a);

            for (int b = 0; b < 9; b++) {
                System.out.println(g.shortest(a, b));                
            }
        }    
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多