5

バックグラウンド

ダイクストラのアルゴリズムをO(mlogn)時間でコーディングしようとしています。ここで、mはエッジの数、nはノードの数です。特定の開始ノードと特定の終了ノードの間の最短パスを見つけるために使用しています。そして、私はこれでかなり新しいです。

これが私が思いついたアルゴリズムです:

グラフが隣接行列で表され、各ノードに行インデックスがあると仮定します。

Initialize starting node distance to zero, and all other nodes to inifinity, in the heap.

Create a list of shortest paths, equal to the number of nodes in the graph, set to 0.

While the index of the node that corresponds to the minimum element in the heap 
has no value in the list of shortest paths and heap has node distances, do:
    Remove the minimum node distance from the heap, and bubble as necessary to fill the removed node.
    Put the minimum node distance into the list of shortest paths at its row index.

    For all nodes that were adjacent to the node with the minimum distance (that was just removed), do:
      Update the distances in the heap for the current node, using the following calculation:
        min((deleted node distance + adjacent edge weight), current node's distance)
    Reorganize the heap to be a minimum heap.

Return value in the list of shortest paths at the location of the end node.

エッジごとに1回だけ距離を更新するため、これはO(mlogn)です。

「ヒープを初期化するには線形の時間がかかります。その後、合計時間O(mlog n)に対してそれぞれO(log n)のコストでm個の更新を実行します。」-http ://www.cs.cmu.edu/~avrim/451f07/lectures/lect1011.pdf

問題

ヒープ内の正しい位置にある開始頂点からの距離を更新するには、ヒープへの挿入はキーと値のペアである必要があります。キーはノード(行インデックス)であり、値は距離です。

優先キューADTの各エントリがキーと値のペアであると述べている講義スライドがオンラインにあります(そうでない場合、どのように優先順位を付けることができますか?)。

質問

PriorityQueueのメソッドには最大で1つのパラメーターがありますが、値に関連付けられたキーをどのように挿入しますか?

これは、特定の名前を持つ単一のファイルで実行する必要があります(つまり、KeyValuePairクラスを実装することはできないと理解していますComparator)。

私はあなたの考えを聞いてみたいです。

4

4 に答える 4

4

アプリケーションにJDKの優先キューの実装を使用するために、Map<Key, Value>に加えてを維持することができますPriorityQueue<Value>。あなたの場合、Keyはノードを表し、ノードValueまでの最短距離を保持するオブジェクトです。ノードまでの距離を更新するには、最初にマップで対応する距離オブジェクトを検索します。次に、距離オブジェクトを優先キューから削除します。次に、距離オブジェクトを更新します。最後に、距離オブジェクトを優先キューに戻します。

于 2012-12-03T18:49:02.340 に答える
2

以下は、priority_queueを使用したDijkstraの実装です。ここでは、高速入力の場合と同様に、InputReaderクラスを無視します。キーと値のペアのペアの「値」に応じて優先順位を維持できます。次に、最小コスト、つまり値のペアを選択します。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.List;
import java.util.PriorityQueue;
/** 
 * By: Rajan Parmar
 * At : HackerRank 
 **/
public class Dijkstra { 
     // node ,pair ( neighbor , cost)
    static HashMap < Integer , HashSet <Pair>> node;
    static PrintWriter w;   
    public static void main(String [] s) throws Exception{
        InputReader in;

        boolean online = false;
        String fileName = "input";

        node = new HashMap<Integer, HashSet<Pair>>();


        //ignore online if false it is for online competition
        if (online) {

            //ignore
            in = new InputReader(new FileInputStream(
                    new File(fileName + ".txt")));
            w = new PrintWriter(new FileWriter(fileName + "Output.txt"));
        } else {

            // for fast input output . You can use any input method
            in = new InputReader(System.in);
            w = new PrintWriter(System.out);
        }

        // Actual code starts here
        int t;
        int n, m;
        t = in.nextInt();

        while(t-- > 0){
            n = in.nextInt();
            m = in.nextInt();
            while(m-- > 0){
                int x,y,cost;
                x = in.nextInt();
                y = in.nextInt();
                cost = in.nextInt();

                if(node.get(x)==null){
                    node.put(x, new HashSet());
                    node.get(x).add(new Pair(y,cost));
                }
                else{
                    node.get(x).add(new Pair(y,cost));
                }
                if(node.get(y)==null){
                    node.put(y, new HashSet());
                    node.get(y).add(new Pair(x,cost));
                }
                else{
                    node.get(y).add(new Pair(x,cost));
                }
            }
            int source = in.nextInt();
            Dijkstra(source,n);
            node.clear();
            System.out.println("");
        }
    }

    static void Dijkstra(int start , int n) {

        int dist[] = new int[3001];
        int visited[] = new int[3001];
        Arrays.fill(dist, Integer.MAX_VALUE);
        Arrays.fill(visited, 0);
        dist[start] = 0 ;
        PriorityQueue < Pair > pq = new PriorityQueue();

        //this will be prioritized according to VALUES (i.e cost in class Pair)
        pq.add(new Pair(start , 0));
        while(!pq.isEmpty()){
            Pair pr = pq.remove();
            visited[pr.neighbor] = 1;
            for(Pair p:node.get(pr.neighbor)){
                if(dist[p.neighbor] > dist[pr.neighbor] + p.cost){
                    dist[p.neighbor] = dist[pr.neighbor] + p.cost;

                    //add updates cost to vertex through start vertex
                    if(visited[p.neighbor]==0)
                        pq.add(new Pair(p.neighbor ,dist[p.neighbor] ));
                }

            }
        }
        for(int i=1;i<=n;i++){
            if(i==start) continue;
            if(visited[i]==0)
                dist[i]=-1;
            System.out.print(dist[i]+" ");
        }
    }

    static class Pair implements Comparable {

        int neighbor;
        int cost;

        public Pair(int y, int cost) {
            // TODO Auto-generated constructor stub
            neighbor = y;
            this.cost = cost;
        }

        @Override
        public int compareTo(Object o) {
            // TODO Auto-generated method stub
            Pair pr = (Pair)o;

            if(cost > pr.cost)
                return 1;
            else
                return -1;

        }

    }

    //Ignore this class , it is for fast input.
    static class InputReader {

        private InputStream stream;
        private byte[] buf = new byte[8192];
        private int curChar, snumChars;
        private SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int snext() {
            if (snumChars == -1)
                throw new InputMismatchException();
            if (curChar >= snumChars) {
                curChar = 0;
                try {
                    snumChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (snumChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        public int nextInt() {
            int c = snext();
            while (isSpaceChar(c))
                c = snext();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = snext();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = snext();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public long nextLong() {
            int c = snext();
            while (isSpaceChar(c))
                c = snext();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = snext();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = snext();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public int[] nextIntArray(int n) {
            int a[] = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        public String readString() {
            int c = snext();
            while (isSpaceChar(c))
                c = snext();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = snext();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public boolean isSpaceChar(int c) {
            if (filter != null)
                return filter.isSpaceChar(c);
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);
        }
    }
}

これは、次の形式で入力されます。

最初の行はT(テストケースの数)です。

各テストケースの次の行入力はNとMになります。ここで、Nはノードの数ではなく、Mはエッジの数ではありません。

次のM行には、3つの整数、つまりx、y、Wが含まれています。これは、ノードxとyの間のエッジを重みWで表します。

次の行には単一の整数、つまりソースノードが含まれています。

出力:

指定されたソースノードからすべてのノードまでの最短距離を出力します。ノードに到達できない場合は-1を出力します。

例えば

入力:

1
6 8
1 2 1
1 5 4
2 5 2
2 3 2
5 6 5
3 6 2
3 4 1
6 4 3
1

出力:(ノード1からのすべてのノードの最短距離)

1 3 4 3 5
于 2016-01-25T12:56:59.887 に答える
0

私の質問に対する回答に感謝します。言語の理解が限られていることを考えると、実装が簡単に思えたため、マップの回答を選択しました。

問題を思ったよりもはるかに単純にする重要な詳細を見落としていたことがわかりました。距離の配列を維持し、ノードを(距離ではなく)ヒープに挿入して、距離の配列への参照として使用する場合、値に基づいてノードを並べ替えることができました。

この実装では、結局、Key-Valueプロパティを考案する必要はありませんでした。@reprogrammerによって提案されているように、距離配列の値を更新した後、ヒープを最新の状態に保ち、並べ替えるために、これらの特定のノードを削除してヒープに再度追加する必要がありました。

ヒープに入れるものを変更すると、アルゴリズムはWikipediaにあるものと非常に似ていました。

誰かが同じ問題を抱えている場合に備えて、私が最終的に使用したコードは次のとおりです。注:魔法の部分はPriorityQueueの作成です(これは@stevevlsによって提案されたものに似ています):

import java.util.*;
import java.io.File; //Because files were used to test correctness.
import java.lang.Math;

public class Dijkstra{

//This value represents infinity.
public static final int MAX_VAL = (int) Math.pow(2,30);

/* Assumptions:
    If G[i][j] == 0, there is no edge between vertex i and vertex j
    If G[i][j] > 1, there is an edge between i and j and the value of G[i][j] is its weight.
    No entry of G will be negative.
*/


static int dijkstra(int[][] G, int i, int j){
    //Get the number of vertices in G
    int n = G.length;

    // The 'i' parameter indicates the starting node and the 'j' parameter
    // is the ending node.


    //Create a list of size n of shortest paths, initialize each entry to infinity
    final int[] shortestPaths = new int[n];

    for(int k = 0; k < n; k++){
        shortestPaths[k] = MAX_VAL;
    }

    //Initialize starting node distance to zero.
    shortestPaths[i] = 0;

    //Make a Priority Queue (a heap)
    PriorityQueue<Integer> PQ = new PriorityQueue<Integer>(n,
        new Comparator<Integer>()
            {
                public int compare(Integer p, Integer q)
                {
                    return shortestPaths[p] - shortestPaths[q];
                }
            } );

    //Populate the heap with the nodes of the graph
    for(int k = 0; k < n; k++){
        PQ.offer(k);
    }

    //While the heap has elements.
    while(PQ.size() > 0){

    //  Remove the minimum node distance from the heap.
        int minimum = PQ.poll();

    //  Check if graph is disconnected, if so, return -1.
        if(shortestPaths[minimum] == MAX_VAL)
            {
                return -1;
            }
    //  End node has been reached (i.e. you've found the shortest path), return the distance.
        if( minimum == j){
            return shortestPaths[j];
        }

    //  Take the current node and look through the row to see the vertices adjacent to it (neighbours)
        for(int columnIt = 0; columnIt < n; columnIt ++){


    //    Update the distances in the heap for the current node, using the following calculation:
    //      min((deleted node distance + adjacent edge weight), current node's distance)

            if(G[minimum][columnIt] > 0){

                int sum = shortestPaths[minimum] + G[minimum][columnIt];

                shortestPaths[columnIt]= Math.min(sum, shortestPaths[columnIt]);

                if(shortestPaths[columnIt]==sum)
                {
                    PQ.remove(columnIt);
                    PQ.offer(columnIt);
                }
            }
        }
    }
    return -1;
}

あなたの答えとアドバイスをありがとう。

于 2012-12-04T20:32:48.987 に答える
0

私は同じ問題を解決しています。私はあなたがあなたの質問に対する答えをどこで見つけることができるか知っています。これは、コードの例が記載された素晴らしい本です-アルゴリズム、ロバート・セッジウィックとケビン・ウェインによる第4版。


サイトブックコード例( PriorityQueueを使用したダイクストラのアルゴリズムの実装を含む)このダイクストラのアルゴリズムの実装は、Javaの標準のPriorityQueue実装を使用していません。代わりに、本の前半で詳細な説明とともに説明したIndexMinPQを実装しています。

于 2014-10-24T10:52:44.137 に答える