最短路
最短路
标签(空格分隔): ACM 最短路 图论
最短路
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
题目:http://acm.hdu.edu.cn/showproblem.php?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<
/****************************************
*****************************************
* 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;
}
整体测试代码
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<cstdio>
#include<queue>
#include<stack>
#include<vector>
#include<functional>
#define INF 99999
using namespace std;
typedef pair<int, int> P;
struct edge {
int from, to, cost;
};
int n, m; //n为顶点数,m为边数
int a[100][100];
void warshall()
{
int b[100][100] = { 0 };
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
b[i][j] = a[i][j];
cout << "Floyd-warshall: \n";
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
if (b[j][k] > b[j][i] + b[i][k])
{
b[j][k] = b[j][i] + b[i][k];
}
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << b[i][j] << " ";
}
cout << endl;
}
}
void Dijkstra()
{
int dis[100] = { 0 };
bool book[100] = { 0 };
int b[100][100] = { 0 };
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
b[i][j] = a[i][j];
for (int i = 1; i <= n; i++)
{
dis[i] = a[1][i];
}
book[1] = 1;
for (int i = 1; i <= n - 1; i++)
{
int minv = INF, min = 0;
for (int i = 1; i <= n; i++)
{
if (!book[i] && minv > dis[i])
{
minv = dis[i]; //在取最小值的过程中可以用堆优化
min = i;
}
}
book[min] = 1;
for (int j = 1; j <= n; j++)
{
if (dis[j] > dis[min] + a[min][j])
{
dis[j] = dis[min] + a[min][j]; //用最短的边对其他所有点进行优化
}
}
}
for (int i = 1; i <= n; i++)
{
cout << dis[i] << " ";
}
cout << endl;
}
void Bellman()
{
int dis[100] = { 0 };
int b[100][100] = { 0 };
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
b[i][j] = a[i][j];
for (int i = 1; i <= n; i++)
dis[i] = INF;
dis[1] = 0;
/*for (int i = 1; i <= n; i++)
{
dis[i] = a[1][i];
}*/
for (int i = 1; i <= n - 1; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
if (dis[k] > dis[j] + a[j][k])
{
dis[k] = dis[j] + a[j][k];
}
}
}
}
for (int i = 1; i <= n; i++)
{
cout << dis[i] << " ";
}
cout << endl;
}
void BellmanQueue()
{
int dis[100] = { 0 };
int b[100][100] = { 0 };
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
b[i][j] = a[i][j];
for (int i = 1; i <= n; i++)
dis[i] = INF;
dis[1] = 0;
queue<int> que;
bool book[100] = { 0 };
que.push(1);
book[1] = 1;
while (que.size())
{
int k = que.front();
que.pop();
for (int i = 1; i <= n; i++)
{
if (dis[i] > dis[k] + b[k][i])
{
dis[i] = dis[k] + b[k][i];
if (!book[i])
{
que.push(i);
book[i] = 1;
}
}
}
book[k] = 0;
}
for (int i = 1; i <= n; i++)
{
cout << dis[i] << " ";
}
cout << endl;
}
void warshall2()
{
vector<edge> G[100];
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int p;
edge q;
cin >> p >> q.to >> q.cost;
G[p].push_back(q);
}
for (int i = 1; i <= n; i++)
{
for (int k = 1; k <= n; k++)
{
for (int j = 0; j < G[k].size(); j++)
{
edge e = G[k][j];
}
}
}
cout << "不会\n";
}
void Dijkstra2()
{
vector<edge> G[100];
int n, m;
cin >> n >> m;
int dis[100] = { 0 };
fill(dis, dis + 100, INF);
dis[1] = 0;
for (int i = 0; i < m; i++)
{
int p;
edge q;
cin >> p >> q.to >> q.cost;
G[p].push_back(q);
}
priority_queue<P, vector<P>, greater<P> >que;
que.push(P(0, 1));
while (que.size())
{
P p= que.top(); que.pop();
for (int i = 0; i < G[p.second].size(); i++)
{
edge e = G[p.second][i];
if (dis[e.to] > dis[p.second] + e.cost)
{
dis[e.to] = dis[p.second] + e.cost;
que.push(P(dis[e.to], e.to));
}
}
}
for (int i = 1; i <= n; i++)
{
cout << dis[i] << " ";
}
cout << endl;
}
void Bellman2()
{
edge G[100];
int n, m;
cin >> n >> m;
int dis[100] = { 0 };
fill(dis, dis + 100, INF);
dis[1] = 0;
for (int i = 0; i < m; i++)
{
cin >> G[i].from >> G[i].to >> G[i].cost;
}
for (int i = 1; i <= n - 1; i++)
{
for (int j = 0; j < m; j++)
{
dis[G[j].to] = min(dis[G[j].to], dis[G[j].from] + G[j].cost);
}
}
for (int i = 1; i <= n; i++)
{
cout << dis[i] << " ";
}
cout << endl;
}
int main()
{
cin >> n >> m;
for(int i=0;i<=n;i++)
for (int j = 0; j <= n; j++)
{
if (i == j) a[i][j] = 0;
else a[i][j] = INF;
}
for (int i = 1; i <= m; i++)
{
int p, q, t;
cin >> p >> q >> t;
a[p][q] = t;
}
cout << "邻接矩阵:\n";
cout << "1:Floyd-warshall 2:Dijkstra 3:Bellman-Ford 4:Bellman队列优化(SPFA)\n";
cout << "邻接表\n";
cout << "5:Floyd-warshall 6:Dijkstra(堆优化) 7:Bellman-Ford\n";
int t;
while (cin >> t)
{
if (t == 1)
{
warshall();
}
else if (t == 2)
{
cout << "Dijkstra:\n";
Dijkstra();
}
else if (t == 3)
{
cout << "Bellman-Ford:\n";
Bellman();
}
else if (t == 4)
{
cout << "Bellman队列优化:\n";
BellmanQueue();
}
else if (t == 5)
{
cout << "Floyd-warshall(邻接表):\n";
warshall2();
}
else if (t == 6)
{
cout << "Dijkstra(堆优化) \n";
Dijkstra2();
}
else if (t == 7)
{
cout << "Bellman-Ford:\n";
Bellman2();
}
}
}