Dijkstra算法講解(單源最短路徑問題求解)

無論是算法分析課程還是Java課程設計,都對有向圖中的最短路徑情有獨鍾,今天準備對單願最短路徑的解決方案進行一下詳解,免得每一次用到都是從頭再來2333

適用條件:

在有向圖中,求一個頂點到其他頂點的最短路徑

首先讓我們先回顧一下,最簡單的多源最短路徑的求法:Floyd算法

實例講解

這裏呢我們通過這個例題對這個算法進行解析:(節選自《啊哈算法》)

題目中的關係如圖所示:

這裏寫圖片描述

這裏呢,我們依舊使用二維數組來存儲頂點之間邊的關係

這裏寫圖片描述

爲了讓最後單源路徑最短的問題方便讀取答案,創建一個1號頂點到其他頂點初始路程的數組dist

這裏寫圖片描述

求解思路

1、首先從距離起點最近的點進行操作,因爲起點1不可能通過其他頂點獲得到達該最近點的最短路徑。
2、那麼我們找到了頂點2,和Floyd方法類似,這個時候我們開始經過頂點2對頂點1的其他邊進行優化。
3、比較dist[3]與dist[2]+e[2][3]的大小關係,如果dist[3]較大,則進行更新,這就使得頂點1到3的最短路徑變短。
4、接下來,再剩下的3,4,5和6號頂點中,繼續尋找離1號起點最近的頂點,進行路徑更新。
5、最終通過其他頂點的優化後的道德單源最短路徑爲:
這裏寫圖片描述

總結算法:

1、通過book[i]是否爲1判斷點i是否已經是最短路徑的頂點集合P中,否則在Q中。
2、在Q中選取一個離起點最近的頂點加入到集合P中,並考察所有的以點u爲起點的邊
3、重複第二步,直到Q爲空

算法實現:

/*
 *C語言實現,最簡
 */
#include <stdio.h>
int main()
{
    int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
    int inf = 99999999;//用inf(infinity的縮寫)存儲一個我們認爲的正無窮值
    //讀入n和m,n表示頂點個數,m表示邊的條數
    scanf("%d %d",&n,&m);
    //初始化
    for(i = 1;i <= n;i++) {
        for(j = 1;j <= n;j++){
            if(i == j) e[i][j] = 0;
            else e[i][j] = inf;
        }
    }
    //讀入邊
    for (int i = 0; i < m; i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        e[t1][t2] = t3;
    }
    //初始化dis數組
    for(i = 1;i <= n;i++) {
        dis[i] = e[1][i];
    }
    //book數組初始化
    for(i = 1;i <= n;i++)
        book[i] = 0;
    book[1] = 1;

    //Dijkstra算法核心語句
    for(i = 1;i <= n - 1;i++)
    {
        //找到離1號頂點最近的頂點
        min = inf;
        for(j = 1;j <= n;i++)
        {
            if(book[j] == 0 && dis[j] < min)
            {
                min = dis[j];
                u = j;
            }
        }
        book[u] = 1;
        for(v = 1;v <= n;v++)
        {
            if(e[u][v] < inf){
                if(dis[v] > dis[u] + e[u][v])
                    dis[v] = dis[u] + e[u][v];
            }
        }
    }
    //輸出最終結果
    for(i = 1;i <= n;i++)
        prntf("%d ",dis[i]);
    getchar();
    getchar();
    return 0;
}
/*
 *Java實現,非最優化解
 */
package com.stortest.path;
import java.util.ArrayList;
import java.util.Scanner;

public class Dijkstra {

    public long[] result;//定義全局變量存儲到各點的最短路徑

    public class Edge{
        public int a,b,c;
        Edge(int a,int b,int c){//聲明構造函數
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }

    public boolean get(int n, int s, Edge[] A) {
        ArrayList<Integer> list = new ArrayList<Integer>();//生成list列表
        //初始化
        result = new long[n];
        boolean[] used = new boolean[n];//存儲訪問狀態
        int[] num = new int[n];
        for(int i = 0;i < n;i++) {
            result[i] = Integer.MAX_VALUE;
            used[i] = false;
        }
        result[s] = 0;     //第s個頂點到自身距離爲0
        used[s] = true;    //表示第s個頂點進入數組隊
        list.add(s);      //第s個頂點入隊


        while(list.size() != 0) {
            int a = list.get(0);   //獲取數組隊中第一個元素
            list.remove(0);         //刪除數組隊中第一個元素
            for(int i = 0;i < A.length;i++) {
                //當list數組隊的第一個元素等於邊A[i]的起點時
                if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].c) { 
                    //判斷 起點到終點的最短路徑 是否可以更新
                    result[A[i].b] = result[A[i].a] + A[i].c;
                    if(!used[A[i].b]) {//如果終點是第一次被遍歷
                        list.add(A[i].b);
                        used[A[i].b] = true;   //表示邊A[i]的終點b已進入數組隊
                    }
                }
            }
           // used[a] = false;        //頂點a出數組對
        }
        return true;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Dijkstra text = new Dijkstra();//創建對象
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        Edge[] A = new Edge[m];//創建內部類對象數組,存儲邊的關係
        for(int i = 0;i < m;i++)
        {
            int a = input.nextInt() - 1;
            int b = input.nextInt() - 1;
            int c = input.nextInt();
            A[i] = text.new Edge(a,b,c);
        }//接收輸入數據
        if(text.get(n,0,A)){//調用子函數,輸出到最遠點的結果
            System.out.println(text.result[text.result.length - 1]);
        }
}

}

改進:

該算法的時間複雜度爲O(N2),對於邊數M少於N2的稀疏圖來說,可以使用鄰接矩陣進行優化,可以使時間複雜度優化到(M+N)logN

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章