最短路问题 小结

最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。 算法具体的形式包括:

确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。


确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。


确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。


全局最短路径问题 -  求图中所有的最短路径。


图的存储结构:http://blog.csdn.net/ncepuzhuang/article/details/8445090


最常用的路径算法有:

1.Floyd算法。

2.Dijkstra算法。

3.Bellman-ford算法。

4.SPFA算法。


下面逐个来讲解。。。

1.Floyd算法。
求多源、无负权边的最短路。时效性较差,时间复杂度O(V^3)。空间复杂度为O(N^2)。是解决任意两点间的最短路径的一种算法。

http://blog.csdn.net/zhangxiangdavaid/article/details/38366923

核心代码:


void floyd(int n)
{
    int i,k,j;
    for(k=0; kmap[i][k]+map[k][j])//如果当前i-->j的距离大于i-->k--->j的距离之和
                    map[i][j]=map[i][k]+map[k][j];//更新从i--->j的最短路径
}




2.Dijkstra算法
求单源、无负权的最短路。时效性较好,时间复杂度为O(V*V+E);
以贪心法选取未被处理的具有最小权值的节点,然后对其的出边进行松弛操作;

http://blog.csdn.net/zhangxiangDavaid/article/details/38360337


核心代码:


int dijkstra (int v)
{
    //初始化
    for (i=1;i<=n;i++)
    {
        vist[i]=0;
        dis[i]=map[v][i];
    }
    //进行n-1次操作  选择最短路
    for (i=1;idis[pos]+map[pos][j])
                dis[j]=dis[pos]+map[pos][j];
        }
    }
    return dis[n];
}



3.Bellman-ford算法
求单源最短路,可以判断有无负权回路(若有,则不存在最短路),时效性较好,时间复杂度O(VE)。和dijkstra一样都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确
的值替代,直至得到最优解。
它的原理是对图进行n-1次松弛操作,得到所有可能的最短路径。其优于dijkstra的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高。但是可以进行优化,提高效率。



负权环判定
因为负权环可以无限制的降低总花费,所以如果发现第n次操作仍可降低花销,
就一定存在负权环。



核心代码:


struct node
{
    int u;//起点
    int v;//终点
    int w;//权值
} p[inf];

int dis[inf];//用来保存远点至当前点的最短路径    迭代更新
//   点数    边数    源点
int nodenum,edgenum,source,i,j;

//初始化
void init ()
{

    scanf ("%d%d%d",&nodenum,&edgenum,&source);
    for (i=0; i<=nodenum; i++)
    {
        dis[i]=inf;
    }
    dis[source]=0;
    for (i=0; i dis[p[j].u] + p[j].w)//松弛操作   更新dis数组
            {
                dis[p[j].v] = dis[p[j].u] + p[j].w;
                flag=1;
            }
        }
        if (flag==0)
            break;
    }
    //判断负环
    //上面两层for循环结束之后  dis数组里保存的就是远点到当前点的最短路
    //如果还能进行松弛操作的话就说明有负环存在
    for (i=0; i dis[p[i].u] + p[i].w)
        {
           
            return ;//存在负环 返回0 还是 1 根据题意而定
        }
    }

}


 
  

4.SPFA算法是Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。(k<

核心代码:

void SPFA(int s,int e)  // s点 到 e点
{
    int l,r,i;
    l=r=0;
    memset(vis,0,sizeof(vis));
    memset (dis,inf,sizeof (dis));
    dis[s]=0;
    q[r++]=s;//进队列
    vis[s]=1;//标记 进队列1
    //不在队列为0
    while(l dis[p] + map[p][i])
            {
                dis[i] = dis[p] + map[p][i];
                if(vis[i]==0)
                {
                    q[r++] = i;
                    vis[i] = 1;
                }
            }
        }
        vis[p] = 0;
    }
    if(dis[e]!= inf)
        printf("%d\n",dis[e]);
    else
        printf("-1\n");
}



你可能感兴趣的:(最短路,小结)