1. 程式人生 > >[圖論]最短路問題 dijkstra演算法

[圖論]最短路問題 dijkstra演算法

今天研究的是圖論中的一類基礎問題:最短路問題

最短路問題是圖論中最基礎的問題,在程式設計競賽試題中也經常出現。最短路是給定兩個定點,在以這兩個點為起點和終點的路徑中,邊的權值和最小的路徑。如果把權值當作距離,考慮最短距離的話就很容易理解了。智力遊戲中的求解最少步數問題也可以說是一種最短路問題。

 單源最短路徑問題,即在圖中求出給定頂點到其它任一頂點的最短路徑。在弄清楚如何求算單源最短路徑問題之前,必須弄清楚最短路徑的最優子結構性質。

一.最短路徑的最優子結構性質

   該性質描述為:如果P(i,j)={Vi....Vk..Vs...Vj}是從頂點i到j的最短路徑,k和s是這條路徑上的一箇中間頂點,那麼P(k,s)必定是從k到s的最短路徑。下面證明該性質的正確性。

   假設P(i,j)={Vi....Vk..Vs...Vj}是從頂點i到j的最短路徑,則有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是從k到s的最短距離,那麼必定存在另一條從k到s的最短路徑P'(k,s),那麼P'(i,j)=P(i,k)+P'(k,s)+P(s,j)<P(i,j)。則與P(i,j)是從i到j的最短路徑相矛盾。因此該性質得證。


1、Dijkstra演算法

由上述性質可知:如果存在一條從i到j的最短路徑(Vi...Vk,Vj),Vk是Vj前面的一頂點,那麼(Vi...Vk)也必定是從i到k的最短路徑。為了求出最短路徑,Dijkstra就提出了以最短路徑長度遞增,逐次生成最短路徑的演算法。譬如對於源定點V0,首先選擇其直接相鄰的定點中長度最短的頂點Vi,那麼當前已知可得從V0到達Vj定點的最短距離dist[j]=min(dist[j],dist[i]+matrix[i][j])。根據這種思路,假設存在G=<V,E>,源頂點為V0,U={V0},dist[i]記錄V0到i的最短距離,path[i]記錄從V0到i路徑上的i前面的一個定點。

1、從V-U中選擇使dist[i]值最小的頂點i,將i加入到U中;

2、更新從i直接相鄰頂點的dist值。(dist[j]=min(dist[j],dist[i]+matrix[i][j]))

3、直到U=V,停止。

最短路 HDU2544

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 
Total Submission(s): 28761    Accepted Submission(s): 12444 

Problem Description

在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的t-shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎? 

Input

輸入包括多組資料。每組資料第一行是兩個整數N、M(N<=100,M<=10000),N表示成都的大街上有幾個路口,標號為1的路口是商店所在地,標號為N的路口是賽場所在地,M則表示在成都有幾條路。N=M=0表示輸入結束。接下來M行,每行包括3個整數A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A與路口B之間有一條路,我們的工作人員需要C分鐘的時間走過這條路。 
輸入保證至少存在1條商店到賽場的路線。 

Output

對於每組輸入,輸出一行,表示工作人員從商店走到賽場的最短時間

Sample Input

2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0

Sample Output 3 2
#include <stdio.h>

#include <algorithm>
#define MAX 0x3f3f3f3f
#define RANGE 101
int cost[RANGE][RANGE];
int d[RANGE];
bool used[RANGE];
int n,m;
using namespace std;
void Dijkstra( int s )
{
    int i,v,u;
    for( i=1; i<=n; ++i )
    {
        used[i]=false;
        d[i]=cost[1][i];
    }
    d[s]=0;

    while( true )
    {
        v=-1;
        for( u=1; u<=n; ++u )
            if( !used[u] && ( v==-1 || d[u]<d[v]) )
                v=u;
        if( v==-1 ) break;
        used[v]=true;

        for( u=1; u<=n; ++u )
            d[u]= min( d[u],d[v]+cost[v][u] );
    }
}

int main()
{
    int A,B,C,i,j;

    while( scanf("%d%d",&n,&m) )
    {
        if( !n && !m )  break;
        // 初始化
        for( i=1; i<=n; ++i )
            for( j=1; j<=i; ++j )
                if( i==j )  cost[i][j]=0;
                else    cost[i][j]=cost[j][i]=MAX;
        for( i=0; i<m; ++i )
        {
            scanf("%d%d%d",&A,&B,&C);
            cost[A][B]=cost[B][A]=C;
        }
        Dijkstra(1);
        printf("%d\n",d[n]);
    }
    return 0;
}