简体   繁体   中英

Dijkstra's algorithm for longest path

EDIT 2: This might be too late, but I figured out the problem, it was me. I misunderstood the project, it asked for the largest bandwidth path not the longest path. which is different but I didn't know until now. So basically in any bandwidth path problem (whether largest or smallest), the weights are not accumulated, the path value is determined by the smallest weight in the path. Think of it as a path of pipes and the water flow is determined by the thinest pipe along the path.

EDIT 1: I fixed the PQ issue, but still not working.

It is an assignment (I admit), but I may fail the whole course if I don't submit it. We are supposed to modify Dijkstra's algorithm to calculate the longest SIMPLE path instead of the shortest path. I couldn't figure out a solution. I searched the Internet and found this (It is even the same problem).

But when I run it, it produces incorrect values. Is there any thing I'm missing ? Why even doesn't it sum the weight with the predecessor ? Why use min ?

Info about the graph: 1. We generate the graph randomly such that each node is connected to about 25% of the other nodes. 2. Weights are positive. 3. There are 25 nodes in the graph.

The question says "Routing Algorithm is the algorithm of finding maximum bandwidth path in a graph. It is based on modification of Dijkstra's algorithm using a Max-Heap structure". Is there any trick in it that may help ?

public class MaxDijkstra {
    Graph graph;
    PriorityQueue<Node> queue;

    public MaxDijkstra(Graph graph, Node s){
        this.graph = graph;
        s.addAttribute("ui.class", "start");
        queue = new PriorityQueue<>(new Comparator<Node>(){
            @Override
            public int compare(Node n1, Node n2) {
                if(Utils.getNodeBW(n1) == Utils.getNodeBW(n2)){
                    return 0;
                }else if(Utils.getNodeBW(n1) < Utils.getNodeBW(n2)){
                    return 1;
                }else{
                    return -1;
                }
            }
        });

        // init
        for(Node n : graph){
            Utils.setNodeBW(n, 0);
        }
        Utils.setNodeBW(s, Float.POSITIVE_INFINITY);

        // add to Q
        for(Node n : graph){
            queue.add(n);
        }

        while(!queue.isEmpty()){
            Node u = queue.remove();
            Iterator<Node> iterator = u.getNeighborNodeIterator();
            while(iterator.hasNext()){
                Node v = iterator.next();
                float min = Float.min(Utils.getNodeBW(u), Utils.getEdgeBW(u.getEdgeBetween(v)));
                if(min > Utils.getNodeBW(v)){
                    Utils.setNodeBW(v, min);
                    Utils.setPreOfNode(v, u);
                }
            }

            // validate PQ
            // I know it is not good, just for debuggin now
            // I will implemnt my own PQ later
            List<Node> list = new ArrayList<>();
            while(!queue.isEmpty()){
                Node w = queue.remove();
                list.add(w);
            }
            for(Node w : list){
                queue.add(w);
            }
        }
    }

    public void printInfo(){
        for(Node n : graph){
            System.out.println("N="+n.getId()+" D="+Utils.getNodeBW(n)+" pre="+ (Utils.getPreOfNode(n) == null ? "NIL" : Utils.getPreOfNode(n).getId()) );
        }
    }

    /**
     * Just to colourise the path
     * @param target 
     */
    public void backtrack(Node target){
        target.addAttribute("ui.class", "end");
        Node currunt = target;
        Node pre = Utils.getPreOfNode(currunt);
        while(pre != null){
            currunt.getEdgeBetween(pre).addAttribute("ui.class", "route");
            currunt = pre;
            pre = Utils.getPreOfNode(currunt);
        }
    }

Sample output: 不是最高带宽

Thank you all in advance.

You can't use Dijkstra's algorithm to find the longest simple path. This problem is NP-hard. In fact, there's no known polynomial solution to it.

If the graph is relatively small, you can use dynamic programming to get an O(2^n * poly(n)) solution, which is feasible for n ~ 20-30 (the state is mask of visited vertices and the last vertex. A transition is adding one vertex if it's possible).

If the graph is large, you can use different heuristics and approximations combined with local optimization techniques to get a good (but not necessarily an optimal) solution.

Try multiplying all weights by -1 to make all of the weights negative. Then you can use the Floyd-Warshall algorithm. The Floyd-Warshall algorithm works with negative weights in a graph that doesn't have a cycle. So, use Floyd-Warshall to find the smallest path, which when multiplied by -1, will be your maximum path in the original graph.

You can't alter elements already in the priority queue. Normally for Dijkstra you need a decrease key function, but the one from the library doesn't support that, so you can just reinsert nodes multiple times into the pq with different BW values. Something like this (regard this as pseudocode :))

    PriorityQueue<pair<Node, int>> queue;

    public MaxDijkstra(Graph graph, Node s){

        queue = new PriorityQueue<>(new Comparator<pair<Node, int>>(){
            @Override
            public int compare(pair<Node, int> n1, pair<Node, int> n2) {
                return n1.second > n2.second;
            }
        });

        // init
        for(Node n : graph){
            Utils.setNodeBW(n, 0);
        }
        Utils.setNodeBW(s, Integer.MAX_VALUE);

        // add to Q
        for(Node n : graph){
            queue.add({n, n.getNodeBW()});
        }

        while(!queue.isEmpty()){
            pair<Node, int> u = queue.remove();
            if (u.second < u.first.getNodeBW()) continue; //important - skip if you already saw better value
            Iterator<Node> iterator = u.getNeighborNodeIterator();
            while(iterator.hasNext()){
                Node v = iterator.next();
                int min = Integer.min(Utils.getNodeBW(u), Utils.getEdgeBW(u.getEdgeBetween(v)));
                if(min > Utils.getNodeBW(v)){
                    Utils.setNodeBW(v, min);
                    queue.insert({v, min});
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM