最短路径问题可以进一步分为单源最短路径和全源最短路径。
l 单源最短路径定义为,给定起始顶点s,找出从s到图中其它各顶点的最短路径。求解单源最短路径的算法主要是Dijkstra算法和Bellman-Ford算法,其中Dijkstra算法主要解决所有边的权为非负的单源最短路径问题,而Bellman-Ford算法可以适用于更一般的问题,图中边的权值可以为负。
l 全源最短路径定义为,找出连接图中各对顶点的最短路径。求解全源最短路径的算法主要有Floyd算法和Johonson算法,其中Floyd算法可以检测图中的负环并可以解决不包括负环的图中的全源最短路径问题;Johonson算法同样也是解决不包含负环的图的全源最短路径问题,但是其算法效率更高。
Dijkstra给我的第一感觉跟Prim有点相似。只是更新权值的方式不同,因为要求的是最短路径,所以每个点的消耗都是累计之前相连的点的消耗。以下是POJ1502的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 120
#define MaxInt 0x3f3f3f3f
int n,m;
int map[N][N],visited[N],low[N];
void Dijkstra()
{
int pos=1,i,j,min;
memset(visited,0,sizeof(visited));
for(i=1;i<=n;i++)
low[i]=map[pos][i];
visited[1]=1;
for(i=1;i<n;i++)
{
min=MaxInt;
for(j=1;j<=n;j++)
if(visited[j]==0&&min>low[j])
{
min=low[j];pos=j;
}
visited[pos]=1;
for(j=1;j<=n;j++)
if(visited[j]==0&&low[j]>low[pos]+map[pos][j])
low[j]=low[pos]+map[pos][j];
}
printf("%d\n",low[pos]);
}
int main()
{
int i,j;
char v[50];
while(scanf("%d",&n)!=EOF)
{
memset(map,MaxInt,sizeof(map));
for(i=1;i<=n;i++)
map[i][i]=0;
m=n*(n-1)/2;
for(i=2;i<=n;i++)
for(j=1;j<i;j++)
{
scanf("%s",&v);
if(strcmp(v,"x")!=0)
map[i][j]=map[j][i]=atoi(v);
}
Dijkstra();
}
return 0;
}
至于Floyd算法求没两个点之间的距离,代码很简单,三个循环就搞定了。水了一题POJ1125,代码如下:
#include <stdio.h>
#include <string.h>
#define N 150
#define MaxInt 0x3f3f3f3f
int n,m;
int map[N][N];
void Floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(map[i][k]+map[k][j]<map[i][j])
map[i][j]=map[i][k]+map[k][j];
}
int main()
{
int i,j,t,pos,min,max;
while(scanf("%d",&n)!=EOF&&n!=0)
{
memset(map,MaxInt,sizeof(map));
for(i=1;i<=n;i++)
map[i][i]=0;
for(i=1;i<=n;i++)
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&j);
scanf("%d",&map[i][j]);
}
}
Floyd();
min=MaxInt;
for(i=1;i<=n;i++)
{
max=0;
for(j=1;j<=n;j++)
if(max<map[i][j])
max=map[i][j];
if(min>max)
{
min=max;
pos=i;
}
}
printf("%d %d\n",pos,min);
}
return 0;
}