使用Dijkstra的最短路径算法设置顶点权重

时间:2017-12-09 04:20:06

标签: graph path shortest-path dijkstra vertex

Java新手。

我想要的是一个代表城市的有向图。大多数顶点只是街道,但有些是具有权重的旅游景点(因为必须留在那里一段时间)。我正在使用Dijkstra的最短路径算法,并且已经制作了一些用于添加顶点的版本'权衡它。

然而,问题在于,当我将顶点设置为巡视站点并赋予其权重时,顶点在首次访问时似乎根本没有权重。然后,当第二次访问顶点时,重量显示出来。我不知道问题出在哪里,但我会猜测这是我不是直接编辑原始变量的地方。

打印输出行标在* *之间。一个是 calculateShortest(),另一个是 calculateMin()

public class Graph
{
    protected HashMap<Integer, GraphNode> ntable = new HashMap<Integer, GraphNode>();
    //a hashmap of every node's edge treemap, in which edges are sorted according to weight of each
    protected HashMap<Integer, TreeMap<Integer, GraphEdge>> etable = new HashMap<Integer, TreeMap<Integer,GraphEdge>>();
}

public class GraphNode
{
    private int val;
    private boolean site;
    private boolean hotel;
    private int time;
    private int distance = Integer.MAX_VALUE;
    private LinkedList<GraphNode> shortest = new LinkedList<GraphNode>();
}

public class GraphEdge implements Comparable<GraphEdge>
{
    private int nd1;
    private int nd2;
    private int weight;
}

public class Path
{
    protected LinkedList<GraphNode> path = new LinkedList<GraphNode>();
    Graph g = new Graph();
    GraphNode start = new GraphNode(0);
    protected HashSet<GraphNode> settled = new HashSet<GraphNode>();
    protected HashSet<GraphNode> unsettled = new HashSet<GraphNode>();

    public Graph calculateShortest(int start)
    {
        g.ntable.get(start).setDist(0);
        unsettled.add(g.ntable.get(start));
        while (unsettled.size() != 0)
        {
            GraphNode current = getLowestCostNode(unsettled);
            unsettled.remove(current);
            TreeMap<Integer, GraphEdge> adjacentE = g.etable.get(current.getVal());
            *
           //printing out below shows vertex has no weight
            System.out.println("Curr: "+ current.getVal() + " " + current.getSiteTime());
            *
            for (GraphEdge edge: adjacentE.values())
            {
                GraphNode adjacent = g.ntable.get(edge.getEnd());
                int cost = edge.getWeight() + current.getSiteTime();
                if (!settled.contains(adjacent))
                {
                    calculateMin(adjacent, cost, current);
                    unsettled.add(adjacent);
                }
            }
            settled.add(current);
        }
    return g;
}

    public GraphNode getLowestCostNode(HashSet<GraphNode> unsettled)
    {
        GraphNode lowestDistNd = null;
        int lowestDist = Integer.MAX_VALUE;
        for (GraphNode nd : unsettled)
        {
            int nodeDist = nd.getDist();
            if (nodeDist < lowestDist)
            {
                lowestDist = nodeDist;
                lowestDistNd = nd;
            }
        }
        return lowestDistNd;
    }

    public void calculateMin(GraphNode evaNd, int cost, GraphNode startNd)
    {
        int startDist = startNd.getDist();
        if (startDist + cost < evaNd.getDist())
        {
            evaNd.setDist(startDist + cost);
            LinkedList<GraphNode> shortest = new LinkedList<GraphNode>(startNd.getShortest());
            shortest.add(startNd);
            evaNd.setShortest(shortest);
            *
            //print out if the node's distance is changed
            System.out.println("Change " + evaNd.getVal() + " " + evaNd.getDist());
            *
        }
    }
}

显示问题的行打印输出(不包括主方法输出):

Curr: 1 0
Change: 2 10
Change: 3 15
Curr: 2 0
Change: 4 22
Change: 6 25
Curr: 3 0
Change: 5 25
Curr: 4 0 //1st time visiting shows no weight
Change: 6 23
Change: 5 24
Curr: 6 0
Curr: 5 0
Curr: 1 0
Curr: 2 0
Curr: 3 0
Curr: 4 30 //2nd time visiting shows weight
Curr: 6 0
Curr: 5 0

对于每个顶点, getDist()返回从源顶点到自身的距离, getCost()返回距离加上权重顶点。

我的主要方法如下。 addNodeEdge()已经过测试,可以很好地运行。我在Dijkstra Algorithm in Java使用示例(见下图),在我的情况下ABCDEF是123456。除了图表,我试图将D(这是顶点4)作为权重为30 的网站。 Visualization of the graph

public static void main (String [] args){
    Path p = new Path();
    p.g.addNodeEdge(1, 2, 10);
    p.g.addNodeEdge(1, 3, 15);
    p.g.addNodeEdge(2, 4, 12);
    p.g.addNodeEdge(2, 6, 15);
    p.g.addNodeEdge(3, 5, 10);
    p.g.addNodeEdge(4, 6, 1);
    p.g.addNodeEdge(4, 5, 2);
    p.g.addNodeEdge(6, 5, 5); 
    p.calculateShortest(1);
    System.out.println(p.g.ntable.get(5).getDist());//print out 24

    p.settled.clear();
    p.unsettled.clear();
    p.g.ntable.get(4).setSite(30);
    p.calculateShortest(1);  
    System.out.println(p.g.ntable.get(5).getDist());//still print out 24
}

我期望到E(顶点5)30和F(顶点6)25的最短路径,因为通过D(顶点4)的权重为30的路径太大。然而,在我改变D的重量之前,我在这里得到的东西是完全相同的,然后才增加了D 的重量。就像我上面解释的那样,我认为问题在于D的体重变化......任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:0)

即使您正在清除已结算和未结算的HashSets,跟踪到目前为止找到的最短路径的变量是GraphNode实例变量距离。在第一次运行calculateShortest之后,节点5的距离不会从值24重置,并且在将节点4的站点时间设置为30之后调用该方法后,当然将保持相同。

一种可能的解决方案是更改calculateShortest()的开头以重置所有节点距离:

public Graph calculateShortest(int start) {
    for (GraphNode n : g.ntable.values()) {
        n.setDist(Integer.MAX_VALUE);
    }
    g.ntable.get(start).setDist(0);
    ...

此外,花了一些时间来解决这个问题,主要是因为你发布的代码格式很糟糕。下次请避免发布嵌套类,并且还要包括所有可能不相关的实现细节,这些细节不是普通的getter / setter(例如addNodeEdge)。你永远不知道那个讨厌的bug可能隐藏在哪里!

相关问题