***************************************转载请注明出处: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
pid=2544
求最短路,我是看《挑战程序设计竞赛》里的书学的。
里面介绍了三种方法: 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 ",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 ",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 ",d[1][n]); } return 0; }