约翰逊的算法不起作用

时间:2016-04-05 08:32:31

标签: java algorithm graph shortest-path

我使用约翰逊的算法来找到通过一些任意顶点序列的最短路径。您可以在此处找到更多相关信息:problem description

以下是我如何解决这个问题,我首先使用Johnson算法来获得有向图的所有对最短路径,然后创建一个仅包含指定顶点的新图。最后,我在新创建的图形上实现Dijkstra算法,以找到从开始到结束的最短路径。我的代码如下所示:

package test;

import static org.junit.Assert.assertTrue;


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import algorithm.graph.Dijkstra;

import algorithm.graph.Johnson;

import dataStructure.Graph.Edge;
import dataStructure.Graph.Vertex;


import dataStructure.Graph;

import java.io.IOException;

public class GraphsTest {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    // Compute all-pairs shortest paths using Johnson's algorithm
    String topofilepath = "D:/Documents/Java/workspace/CodeCraftTest/data/case4/topo.csv";
    final Graph<Integer> graph1 = new Graph<Integer>(Graph.TYPE.DIRECTED);
    final int numOfVertices1 = BuildDirectedGraph(topofilepath, graph1);
    System.out.println(numOfVertices1);
    // System.out.println(graph1.getVertices());
    final Map<Vertex<Integer>, Map<Vertex<Integer>, List<Edge<Integer>>>> path = Johnson.getAllPairsShortestPaths(graph1);
    assertTrue("Directed graph contains a negative weight cycle.", (path != null));
    // Code for debug
    for  (Vertex<Integer> vertex1 : path.keySet()){
        final Map<Vertex<Integer>, List<Edge<Integer>>> map1 = path.get(vertex1);
        for (Vertex<Integer> vertex2 : map1.keySet()){
            final List<Edge<Integer>> list1 = map1.get(vertex2);
            final Iterator<Edge<Integer>> iter1 = list1.iterator();
            while (iter1.hasNext()){
                Edge<Integer> e1 = (Edge<Integer>) iter1.next();
                System.out.println(e1);
            }
        }
    }

    // Create a new graph that only contains the specified vertices in demand file
    final Graph<Integer> graph2 = new Graph<Integer>(Graph.TYPE.DIRECTED);
    String demandfilepath = "D:/Documents/Java/workspace/CodeCraftTest/data/case4/demand.csv";
    final int numOfVertices2 = BuildDemandedGraph(demandfilepath, path, graph2);
    System.out.println(numOfVertices2);
    // System.out.println(graph2.getVertices());

    // Implement Dijkstra's algorithm on the specified directed graph
     BufferedReader b = null;
     String line = "";
     String csvSplitBy = ",";
     int startID;
     int endID;

     final Graph.Vertex<Integer> start;
     final Graph.Vertex<Integer> end;

     try{
         b = new BufferedReader(new FileReader(demandfilepath));
         if ((line = b.readLine()) != null){
             String[] entry = line.split(csvSplitBy);
             startID = Integer.parseInt(entry[0]);
             endID = Integer.parseInt(entry[1]);
             start = new Graph.Vertex<Integer>(startID);
             end = new Graph.Vertex<Integer>(endID);
             final Graph.CostPathPair<Integer> pair1 = Dijkstra.getShortestPath(graph2, start, end);
             // System.out.println(pair1.getPath());
         }
     }
     catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }
        finally{
            if (b != null){
                try{
                    b.close();
                }
                catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
}

private static int BuildDirectedGraph(String topofilepath, Graph<Integer> graph) {
    String csvFile = topofilepath;
    BufferedReader br = null;
    String line = "";
    String csvSplitBy = ",";
    String LinkID;
    String SourceID;
    String DestinationID;
    String Cost;
    int linkID;
    int sourceID;
    int destinationID;
    int cost;

    try{
        br = new BufferedReader(new FileReader(csvFile));
        while ((line = br.readLine()) != null)
        {
            String[] entry = line.split(csvSplitBy);
            LinkID = entry[0];
            SourceID = entry[1];
            DestinationID = entry[2];
            Cost = entry[3];

            linkID = Integer.parseInt(LinkID);
            sourceID = Integer.parseInt(SourceID);
            destinationID = Integer.parseInt(DestinationID);
            cost = Integer.parseInt(Cost);

            final Graph.Vertex<Integer> v1 = new Graph.Vertex<Integer>(sourceID);
            final Graph.Vertex<Integer> v2 = new Graph.Vertex<Integer>(destinationID);
            final Graph.Edge<Integer> edge = new Graph.Edge<Integer>(cost, v1, v2);
            if(graph.getVertices().contains(v1) == false)
            {
                graph.addVertex(v1);
            }
            if(graph.getVertices().contains(v2) == false)
            {
                graph.addVertex(v2);
            }
            graph.addEdge(edge);
        }
    }
    catch(FileNotFoundException e)
    {
        e.printStackTrace();
    }
    catch(IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        if (br != null)
        {
            try{
                br.close();
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    }
    return graph.getVertices().size();
}

private static int BuildDemandedGraph(String demandfilepath, Map<Vertex<Integer>, Map<Vertex<Integer>, List<Edge<Integer>>>> path, Graph<Integer> graph)
{
    String csvFile = demandfilepath;
    BufferedReader br = null;
    String line = "";
    String csvSplitBy = ",";

    int startID;
    int endID;
    int cost = 0;

    try{
        br = new BufferedReader(new FileReader(csvFile));
        if ((line = br.readLine()) != null)
        {
            String[] entry = line.split(csvSplitBy);
            startID = Integer.parseInt(entry[0]);
            endID = Integer.parseInt(entry[1]);
            final Graph.Vertex<Integer> start = new Graph.Vertex<Integer>(startID);
            final Graph.Vertex<Integer> end = new Graph.Vertex<Integer>(endID);
            if(graph.getVertices().contains(start) == false)
            {
                graph.addVertex(start);
            }
            if(graph.getVertices().contains(end) == false)
            {
                graph.addVertex(end);
            }

            String[] seqOfVertices = entry[2].split("\\|");
            // System.out.println(seqOfVertices.length);
            for (int i = 0; i < seqOfVertices.length; i++)
            {
                int vertexID = Integer.parseInt(seqOfVertices[i]);
                final Graph.Vertex<Integer> v = new Graph.Vertex<Integer>(vertexID);
                if (graph.getVertices().contains(v) == false)
                {
                    graph.addVertex(v);
                }
            }
            for (Graph.Vertex<Integer> v1 : graph.getVertices()){
                for (Graph.Vertex<Integer> v2 : graph.getVertices()){
                    // debug
                    // System.out.println(v1.getValue());
                    for (Vertex<Integer> vertex : path.keySet()){
                        if (v1.equals(vertex)){
                            final Map<Vertex<Integer>, List<Edge<Integer>>> map1 = path.get(v1);
                            for (Vertex<Integer> v : map1.keySet()){
                                if (v.equals(v2)){
                                    final List<Edge<Integer>> list1 = map1.get(v);
                                    final Iterator<Edge<Integer>> iter1 = list1.iterator();
                                    while(iter1.hasNext()){
                                        Edge<Integer> e1 = (Edge<Integer>) iter1.next();
                                        System.out.println(e1.getCost());
                                        cost += e1.getCost();
                                    }
                                }
                            }
                            final Graph.Edge<Integer> edge = new Graph.Edge<Integer>(cost, v1, v2);
                            graph.addEdge(edge);
                        }
                        if (v2.equals(vertex)){
                            final Map<Vertex<Integer>, List<Edge<Integer>>> map2 = path.get(v2);
                            for (Vertex<Integer> v : map2.keySet()){
                                if (v.equals(v1)){
                                    final List<Edge<Integer>> list2 = map2.get(v);
                                    final Iterator<Edge<Integer>> iter2 = list2.iterator();
                                    while(iter2.hasNext()){
                                        Edge<Integer> e2 = (Edge<Integer>) iter2.next();
                                        cost += e2.getCost();
                                    }
                                }
                            }
                            final Graph.Edge<Integer> edge = new Graph.Edge<Integer>(cost, v2, v1);
                            graph.addEdge(edge);
                        }
                    }
                }
            }
        }
    }
    catch(FileNotFoundException e){
        e.printStackTrace();
    }
    catch(IOException e){
        e.printStackTrace();
    }
    finally{
        if (br != null){
            try{
                br.close();
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    }
    return graph.getVertices().size();
}
}

Johnson的算法是由Justin Wetherell编写的,但在这种情况下它并不起作用,我已经验证图形是否已正确创建,但返回的所有最短路径都是空列表。我找不到问题。你能帮我发现一些可能导致这个问题的错误。

package algorithm.graph;


import java.util.HashMap;
import java.util.List;
import java.util.Map;

import dataStructure.Graph;

/**
 * Johnson's algorithm is a way to find the shortest paths between all pairs of
 * vertices in a sparse directed graph. It allows some of the edge weights to be
 * negative numbers, but no negative-weight cycles may exist.
 * 
 * Worst case: O(V^2 log V + VE)
 * 
 * @author Justin Wetherell <phishman3579@gmail.com>
 */

public class Johnson {

private Johnson() { }

public static Map<Graph.Vertex<Integer>, Map<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>>> getAllPairsShortestPaths(Graph<Integer> g) {
    if (g == null)
        throw (new NullPointerException("Graph must be non-NULL."));

    // First, a new node 'connector' is added to the graph, connected by zero-weight edges to each of the other nodes.
    final Graph<Integer> graph = new Graph<Integer>(g);
    final Graph.Vertex<Integer> connector = new Graph.Vertex<Integer>(Integer.MAX_VALUE);

    // Add the connector Vertex to all edges.
    for (Graph.Vertex<Integer> v : graph.getVertices()) {
        final int indexOfV = graph.getVertices().indexOf(v);
        final Graph.Edge<Integer> edge = new Graph.Edge<Integer>(0, connector, graph.getVertices().get(indexOfV));
        connector.addEdge(edge);
        graph.getEdges().add(edge);
    }

    graph.getVertices().add(connector);

    // Second, the Bellman鈥揊ord algorithm is used, starting from the new vertex 'connector', to find for each vertex 'v'
    // the minimum weight h(v) of a path from 'connector' to 'v'. If this step detects a negative cycle, the algorithm is terminated.
    final Map<Graph.Vertex<Integer>, Graph.CostPathPair<Integer>> costs = BellmanFord.getShortestPaths(graph, connector);

    // Next the edges of the original graph are re-weighted using the values computed by the Bellman鈥揊ord algorithm: an edge 
    // from u to v, having length w(u,v), is given the new length w(u,v) + h(u) 鈭� h(v).
    for (Graph.Edge<Integer> e : graph.getEdges()) {
        final int weight = e.getCost();
        final Graph.Vertex<Integer> u = e.getFromVertex();
        final Graph.Vertex<Integer> v = e.getToVertex();

        // Don't worry about the connector
        if (u.equals(connector) || v.equals(connector)) 
            continue;

        // Adjust the costs
        final int uCost = costs.get(u).getCost();
        final int vCost = costs.get(v).getCost();
        final int newWeight = weight + uCost - vCost;
        e.setCost(newWeight);
    }

    // Finally, 'connector' is removed, and Dijkstra's algorithm is used to find the shortest paths from each node (s) to every 
    // other vertex in the re-weighted graph.
    final int indexOfConnector = graph.getVertices().indexOf(connector);
    graph.getVertices().remove(indexOfConnector);
    for (Graph.Edge<Integer> e : connector.getEdges()) {
        final int indexOfConnectorEdge = graph.getEdges().indexOf(e);
        graph.getEdges().remove(indexOfConnectorEdge);
    }

    final Map<Graph.Vertex<Integer>, Map<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>>> allShortestPaths = new HashMap<Graph.Vertex<Integer>, Map<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>>>();
    for (Graph.Vertex<Integer> v : graph.getVertices()) {
        final Map<Graph.Vertex<Integer>, Graph.CostPathPair<Integer>> costPaths = Dijkstra.getShortestPaths(graph, v);
        final Map<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>> paths = new HashMap<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>>();
        for (Graph.Vertex<Integer> v2 : costPaths.keySet()) {
            final Graph.CostPathPair<Integer> pair = costPaths.get(v2);
            paths.put(v2, pair.getPath());
        }
        allShortestPaths.put(v, paths);
    }
    return allShortestPaths;
}
}

0 个答案:

没有答案