24h購物| | PChome| 登入
2010-12-21 14:42:33| 人氣10,210| 回應2 | 上一篇 | 下一篇

[C#] 最短路徑(Shortest Path)

推薦 0 收藏 0 轉貼0 訂閱站台

最短路徑(Shortest Path)

對一個 n 個節點的網路(如下圖),已知連結各節點的路徑及其加權(weight),求出由網路中的一個節點至其他節點間的最短距離。 

 

      
       圖1. 網路圖

 Dijkstra最短路徑演算法所需的資料結構 

 

         圖2.網路加權鄰接矩陣

二維陣列 Cost( , )

儲存相鄰節點路徑的加權值,Cost(i, j)表節點 i 和相鄰節點 j間的路徑距離。

Cost(i, j) =  表節點 i 和 j間並無直接連結。

 



                                                    圖3

  Dist( ) 陣列儲存起始節點 V0 至各節點間的距離,經演算法計算後,最後會儲存V0到其他各點間的最短距離。

若此陣列經演算法後,其值如圖3.所示,可知:

節點 0 至節點 4 的最短路徑為10.

節點 0 至節點 7 的最短路徑為9.

 



                                                   圖4.

PreNode( )陣列儲存各節點至起始點最短路徑的前一個節點。

 

若此陣列經演算法後,其值如圖4.所示,可知:

節點0至節點4的行經節點為 0 -> 3 -> 5 -> 7->4。

節點0至節點7的行經節點為 0 -> 3 -> 5 -> 7。

 



                                                   圖5.

Decided( )陣列儲存起始節點到各節點間的最短路徑是否已經被找到。起始值除起始點設為1外,其他各節點皆設為 0。如起始點為節點0, 則節點0設1,其他節點皆設為0;如起始節點為節點1,則節點1設為1,其餘節點皆設為0,依此類推。

 Dijkstra演算法步驟:

step 1:

假設起始節點為0,Dist( )陣列預設為每一個節點與起始節點 0間的路徑距離,NC表示節點與起始節點0間沒有直接連結,程式將NC設為一個遠大於路徑距離的值100000。

PreNode( )陣列中每一個節點的前一節點預設為起始節點0,若起始節點為節點1則全設為1,依此類推。

Decided( )除起始節點設為1(本例起始節點為節點0),其餘節點皆設為0 表示尚未決是短路徑。



                                                     圖6.

Step 2:

由Decided ( )陣列中尚未決定最小路徑的節點中(Decided(i) = 0)找出最短路徑(Dist(i)最小)的節點 Nd,將Decided(Nd)設為1,表示已決定最短距離,並檢查其他尚未決定的節點 w 是否可經由此節點縮短與起始節點間的路徑距離,如Dist(w) > Dist(Nd) + Cost(Nd, w),Dist(w) = Dist(Nd) + Cost(Nd, w)。

圖7表示: 節點1已找到最短路徑,沒有其他的節點經由其縮短路徑距離。



                                                        圖7.

 

圖8 表示:節點3已找到最短距離,節點4和5可經由節點3縮短路徑距離。



                                                        圖8.

經重複Step 2 流程,當Decided() 皆為1時,可由圖3和圖4的Dist( )陣列和PreNode( )陣列得出所有所有節點的最短路徑距離及路徑上的所有節點,

執行結果: 





程式碼如下:

// =========================================================
//       從某一點到其餘各點的最短路徑
//         Dijkstra() Dijkstra演算法
//         find_Shortest() 找出Decided[]=0且Dist最小者
//         Dist(N) 從起點到各點的最短距離
//         PreNode(N) 各點最短路徑中的前一個頂點
//         Decided(N) 最短路徑是否已決定
//        作者: Chris C.S Huang
//        程式語言: VC# 2008 Expression Edition
//=========================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    class Program
    {

        public const int N = 8;                  //N是總頂點數
        const int NC = 100000;               //表二節點間沒有直接連結
       //路網圖, NC表示沒有直接連接
        public static int[,] Cost = new int[,]  {{ 0,  3,  5,  4, NC, NC, NC, NC},      
                                                 { 3,  0, NC,  4, NC, NC, NC, NC},
                                                 { 5, NC,  0,  3, NC,  2, NC, NC},
                                                 { 4,  4,  3,  0,  7,  3, NC, NC},
                                                 {NC, NC, NC,  7,  0, NC,  6,  1},
                                                 {NC, NC,  2,  3, NC,  0,  4,  2},
                                                 {NC, NC, NC, NC,  6,  4,  0,  3},
                                                 {NC, NC, NC, NC,  1,  2,  3,  0}};

        public static int[] Dist = new int[N];
        public static int[] Decided = new int[N];
        public static int[] PreNode = new int[N];
        public static int Start;

        static void Main(string[] args)
        {
           
             int i;
             Console.WriteLine("求某一節點到其他節點間的距離.");
             Console.Write("請輸入起點(0-7): ");
             try{
                 Start = Convert.ToInt16(Console.ReadLine());
             }
            catch(Exception ex)
             {
                 Console.WriteLine(ex.Message);
                 Console.WriteLine("Wrong Input!  Press any key to Exit");
                 Console.Read();
                 System.Environment.Exit(1);
                
            }

             if(Start > 7 || Start < 0)
            {
                Console.WriteLine("Wrong Input!  Press any key to Exit");
                Console.Read();
                System.Environment.Exit(1);
            }

             Dijkstra(Start);
            for(i = 0; i < N; i++)
            {
                if(i != Start)
                {
                    Console.WriteLine("V{0} --> V{1}  Distance == {2}", Start, i, Dist[i]);    //Dist陣列是行進距離
                    PrintPath(Start, i);
                }

            }
         
        Console.WriteLine("Press Enter key to Exit");
        Console.Read();
     
        }
        unsafe public static void Dijkstra(int Start)  ///Start是指定的起點, 例如0表示N0 ; 編譯時必須使用Unsafe選項
        {
            int Nd, i, w;
            for(i = 0; i < N; i++)
            {
         Dist[i] = Cost[Start, i];                         //初設為Cost[]陣列的第Start列
               PreNode[i] = Start;                                 //由Start開始走到任意一點
               Decided[i] = 0;
            }
            Decided[Start] = 1;
            for(i = 0; i < N; i++)
            {
                find_Shortest(&Nd);                          ///找尚未找過且與V0最近的節點Nd
                if (PreNode[Nd] == -1)
                    PreNode[Nd] = Start;
                Decided[Nd] = 1;
                for(w = 0; w < N; w++)
                {
                    if(Decided[w] == 0 && Dist[w] > (Dist[Nd] + Cost[Nd, w]))
                    {
                    Dist[w] = Dist[Nd] + Cost[Nd, w];
                    PreNode[w] = Nd;
                    }

                }
            }
        }
    
        unsafe static void find_Shortest(int* Nd)    //找出連接目前節點的所有點中距離最短的節點Nd
        {
            int low = 0, lowest = 32767, i = 0;
            for(i = 0; i < N; i++)
            {
                if(Decided[i]==0 && Dist[i] < lowest)
                {
                     lowest = Dist[i];
                     low = i;
                }
            }
            *Nd = low;
        }
  
        public static void PrintPath(int Start, int Nd) // Start: 起始點, Nd終點
        {
          int i;
          Stack<int> stack = new Stack<int>();
          stack.Push(Nd);
          i = PreNode[Nd];
          while(i != Start)
          {
              stack.Push(i);
              i = PreNode[i];
          }
              stack.Push(i);
              Console.Write("經過節點 : ");

              while (stack.Count > 0)
              {
                  Console.Write("{0} ", stack.Pop());
              }
            Console.WriteLine();
        }    
       
    }
}

台長: Chris C.S Huang
人氣(10,210) | 回應(2)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 不分類 | 個人分類: 資料結構 |
此分類下一篇:[C#]最短路徑(視窗版)
此分類上一篇:[C#]河內塔(Towers of Hanoi)

(悄悄話)
2011-03-20 17:03:15
(悄悄話)
2011-03-29 15:49:55
是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文