有关最短路径的算法主要有Floyd-Warshall,Dijsktra,Bellman-Ford,SPFA等算法,各有各的优点,这里做一个总结,总结一下这几天的思绪。
Floyd-Warshall算法:
简单暴力,通过不断松弛,找出两点之间的最短路径(遍历整个图,如果有e[i][j]>e[i][k]+e[k][j],就把e[i][j]更新为e[i][k]+e[k][j],可以通过三层循环暴力循环来解出来),缺点是不能处理负权边,时间复杂度为O(N^3).代码实现如下:
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
for(k=1;k<=n;k++)
if(a[j][i]!=inf&&a[i][k]!=inf&&a[j][k]>a[j][i]+a[i][k])
a[j][k]=a[j][i]+a[i][k];
Dijsktra算法:
Dijsktra算法主要用来解决单源最短路径问题,就拿从1号顶点出发到节点n来说,先把各个点到源点1的路径长度存入数组dis,即:
for(i=1;i<=n;i++)
dis[i]=e[1][i];
存入之后把节点1用book数组标记一下,然后从小到大遍历dis数组,找出跟1相连的最小边,假设j节点离1最近,就从j节点开始找并把j节点标记一下,如果dis[j]+a[j][k]
for(i=1;i<=n;i++)
dis[i]=a[1][i];
book[1]=1;
c=1;
while(c<n)
{
min=inf;
for(i=1;i<=n;i++)
{
if(book[i]==0&&min>dis[i])
{
min=dis[i];
j=i;
}
}
book[j]=1;
c++;
for(i=1;i<=n;i++)
{
if(dis[i]>dis[j]+a[j][i])
{
dis[i]=dis[j]+a[i][j];
}
}
}
Bellman-Ford算法:
Bellman-Ford可以解决负权边的问题,源点到所有点最短路径问题。(最短路径肯定不包含回路,如果有正权回路,减去该回路所得值一定最小,如果是负权回路,那么就没有最小值)主要思想是“松弛”,跟Dijsktra很相似,所谓松弛就是如果2条边的和小于第三条边,就把第三条边的值赋为另两边的和,每一次都把所有的m条边遍历一遍,因为有n个顶点,所以有n-1条边,所以遍历n-1次。如果进行n-1次松弛之后,还能进行松弛,就说明路径中含有负权边。时间复杂度为O(NM).
代码实现如下:
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
}
for(i=1;i<=n;i++)
{
dis[i]=inf;
}
dis[1]=0;
for(k=1;k<=n-1;k++)
{
for(i=1;i<=m;i++)
{
if(dis[v[i]]>dis[u[i]]+w[i])
{
printf("%d! ",dis[v[i]]);
dis[v[i]]=dis[u[i]]+w[i];
printf("%d# ",dis[v[i]]);
}
}
printf("\n");
}
for(i=1;i<=n;i++)
printf("%d ",dis[i]);
printf("\n");
算法还能进行一些优化,如果在第n-1次松弛之前dis数组就不再进行变化,就直接跳出输出。(也就在每次松弛之前存储dis数组,松弛之后进行比对,如果有不一样的元素,就继续松弛,否则就跳出,这样可以优化算法的时间复杂度)
SPFA算法:
尚未研究,等待最新更新。