最短路径问题

来源:互联网 发布:淘宝手办黑店 编辑:程序博客网 时间:2024/06/07 19:31

有关最短路径的算法主要有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,即:

fori=1i<=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算法:
尚未研究,等待最新更新。

原创粉丝点击