***************************************轉載請注明出處:http://blog.csdn.net/lttree***************************************
最短路
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 28761 Accepted Submission(s): 12444
所以如今他們想要尋找最短的從商店到賽場的路線,你能夠幫助他們嗎?
每組數據第一行是兩個整數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條商店到賽場的路線。
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
3 2
求最短路,我是看《挑戰程序設計競賽》里的書學的。
里面介紹了三種方法: Bellman-Ford、Dijkstra and Floyd
三者差別也都非常明顯:
Bellman-Ford:
求單源最短路,能夠推斷有無負權回路(若有。則不存在最短路)。 時效性較好,時間復雜度O(VE)。
Bellman-Ford算法是求解單源最短路徑問題的一種算法。
單源點的最短路徑問題是指: 給定一個加權有向圖G和源點s,對於圖G中的隨意一點v。求從s到v的最短路徑。
與Dijkstra算法不同的是,在Bellman-Ford算法中。邊的權值能夠為負數。
設想從我們能夠從圖中找到一個環路(即從v出發,經過若干個點之后又回到v)且這個環路中全部邊的權值之和為負。
那么通過這個環路。環路中隨意兩點的最短路徑就能夠無窮小下去。假設不處理這個負環路。程序就會永遠執行下去。 而Bellman-Ford算法具有分辨這樣的負環路的能力。
Dijkstra:
求單源、無負權的最短路。時效性較好,時間復雜度為O(V*V+E)。 源點可達的話,O(V*lgV+E*lgV)=>O(E*lgV)。
當是稀疏圖的情況時,此時E=V*V/lgV,所以算法的時間復雜度可為O(V^2) 。
若是斐波那契堆作優先隊列的話。算法時間復雜度。則為O(V*lgV + E)。
Floyd:
求多源、無負權邊的最短路。用矩陣記錄圖。時效性較差,時間復雜度O(V^3)。 Floyd-Warshall算法(Floyd-Warshall algorithm)是解決隨意兩點間的最短路徑的一種算法,能夠正確處理有向圖或負權的最短路徑問題。
Floyd-Warshall算法的時間復雜度為O(N^3),空間復雜度為O(N^2)。
Floyd-Warshall的原理是動態規划: 設Di,j,k為從i到j的僅僅以(1..k)集合中的節點為中間節點的最短路徑的長度。 若最短路徑經過點k。則Di,j,k = Di,k,k-1 + Dk,j,k-1。 若最短路徑不經過點k。則Di,j,k = Di,j,k-1。
因此。Di,j,k = min(Di,k,k-1 + Dk,j,k-1 , Di,j,k-1)。
在實際算法中,為了節約空間,能夠直接在原來空間上進行迭代,這樣空間可降至二維。 Floyd-Warshall算法的描寫敘述例如以下: for k ← 1 to n do for i ← 1 to n do for j ← 1 to n do if (Di,k + Dk,j < Di,j) then Di,j ← Di,k + Dk,j; 當中Di,j表示由點i到點j的代價,當Di,j為 ∞ 表示兩點之間沒有不論什么連接。
后來,我看Bellman-Ford的隊列優化,SPFA(Shortest Path Faster Algorithm )。
SPFA:
是Bellman-Ford的隊列優化,時效性相對好,時間復雜度O(kE)。(k<<V)。
與Bellman-ford算法類似,SPFA算法採用一系列的松弛操作以得到從某一個節點出發到達圖中其他全部節點的最短路徑。
所不同的是。SPFA算法通過維護一個隊列,使得一個節點的當前最短路徑被更新之后沒有必要立馬去更新其他的節點,從而大大降低了反復的操作次數。
SPFA算法能夠用於存在負數邊權的圖,這與dijkstra算法是不同的。
與Dijkstra算法與Bellman-ford算法都不同。SPFA的算法時間效率是不穩定的,即它對於不同的圖所須要的時間有非常大的區別。
在最好情形下,每個節點都僅僅入隊一次,則算法實際上變為廣度優先遍歷。其時間復雜度僅為O(E)。
還有一方面,存在這種樣例,使得每個節點都被入隊(V-1)次。此時算法退化為Bellman-ford算法,其時間復雜度為O(VE)。
SPFA算法在負邊權圖上能夠全然代替Bellman-ford算法。另外在稀疏圖中也表現良好。可是在非負邊權圖中,為了避免最壞情況的出現,通常使用效率更加穩定的Dijkstra算法,以及它的使用堆優化的版本號。通常的SPFA算法在一類網格圖中的表現不盡如人意。
然后,這道題我用了SPFA,Dijkstra和Floyd來做(Bellman-Ford 太慢。就不做了)
這道題。當時我怎么做,做不出來,后來發現是 MAX 設定為 0x7fffffff 問題。設置成別的大數就沒事。
貢獻了N個WA啊。。!
郁悶ING。
。。
SPFA:
/**************************************** ***************************************** * Author:Tree * *From :http://blog.csdn.net/lttree * * Title : 最短路 * *Source: hdu 2544 * * Hint : SPFA * ***************************************** ****************************************/ #include <stdio.h> #include <queue> using namespace std; #define RANGE 101 #define MAX 0x3f3f3f3f int cost[RANGE][RANGE]; int d[RANGE]; bool used[RANGE]; int n,m; void spfa( int s ) { int i,now; // 初始化 for( i=1;i<=n;++i ) { d[i]=MAX; used[i]=false; } d[s]=0; queue <int> q; q.push(s); used[s] = true; while(!q.empty()) { now = q.front(); q.pop(); used[now] = false; for(i = 1; i <= n; i++) { if(d[i] > d[now] + cost[now][i]) { d[i] = d[now] + cost[now][i]; if(used[i] == 0) { q.push(i); used[i] = true; } } } } } int main() { int i,j,A,B,C; 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; } spfa(1); printf("%d\n",d[n]); } return 0; }
Dijkstra:
/**************************************** ***************************************** * Author:Tree * *From :http://blog.csdn.net/lttree * * Title : 最短路 * *Source: hdu 2544 * * Hint : Dijkstra * ***************************************** ****************************************/ #include <stdio.h> #define MAX 0x3f3f3f3f #define RANGE 101 int cost[RANGE][RANGE]; int d[RANGE]; bool used[RANGE]; int n,m; int Min( int a,int b ) { return a<b?a:b; } 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; }
Floyd:
/**************************************** ***************************************** * Author:Tree * *From :http://blog.csdn.net/lttree * * Title : 最短路 * *Source: hdu 2544 * * Hint : Floyd * ***************************************** ****************************************/ #include <stdio.h> #define MAX 0x3f3f3f3f #define RANGE 105 int d[RANGE][RANGE]; int n; int Min( int a,int b ) { return a<b?a:b; } void warshall_floyd( void ) { int i,j,k; for( k=1;k<=n;++k ) for( i=1;i<=n;++i ) for( j=1;j<=n;++j ) d[i][j]=Min( d[i][j],d[i][k]+d[k][j] ); } int main() { int m,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 ) d[i][j]=0; else d[i][j]=d[j][i]=MAX; } // 輸入 for( i=0;i<m;++i ) { scanf("%d%d%d",&A,&B,&C); d[A][B]=d[B][A]=C; } // floyd算法求最短路 warshall_floyd(); printf("%d\n",d[1][n]); } return 0; }