最短路的四种算法

求最短路一般有四种方法:

1.floyd       dp思想dis[i][j]=min(dis[i][j]+dis[i][k]+dis[k][j])                                 时间复杂度O(N^3)
2.dijkstra    邻接矩阵。                                                                                  时间复杂度O(N^2)
 
 
 
3.dijkstra    邻接表+优先级队列优化。                                                           时间复杂度O(M*lgN)
4.bellman-Ford 用于解决含有负权值得最小路问题                                        时间复杂度O(M*N)    
5.SPFA是bellman-ford的改进算法(队列实现),效率也更高                         复杂度为:O(kE)E为边数,k一般为2或3
1.floyd算法:可以求任意两点之间的最短距离。解决传递背包和最小环问题~,不能解决负权回路。
for(int k=0;k<a;k++)//经过k点
{
    for(int i=0;i<a;i++)//起点
    {
        for(int j=0;j<a;j++)//终点
        {
            If(w[i][j]>w[i][k]+w[k][i];
            w[i][j]=w[i][k]+w[k][i];
        }
     }
}//如果经过k点距离变短,那么w[i][j]不变,否则更新。
可以理解为对于1点而言,经过或者不经过1点求个最短,然后在1点的基础上对于2点,求个最短路...。
2.dijkstra 邻接矩阵:没办法解决负边权的最短路径。
采用的是邻接矩阵来存的,第一点浪费的空间比较多,第二点我们知道算法的时间复杂度在O(n*n)

(1)确定数组—邻接矩阵(赋值0或者inf)

(2)输入数组-邻接矩阵

(3)确定距离dis数组//用1号顶点到其余各边的距离初始化;

(4)判断某一点是否当过起始点bool数组

(5)最关键!!循环n-1次,

          先找一行中的最小值确保该行没有遍历过。

         找到之后通过最小值所在行更新dis数组。

      //初始化
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(i==j) e[i][j]=0;  
              else e[i][j]=inf;
              
    //读入边和权值
    for(i=1;i<=m;i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        e[t1][t2]=t3;
    }

    //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
    for(i=1;i<=n;i++)
        dis[i]=e[1][i];

    //book数组初始化
    for(i=1;i<=n;i++)
        book[i]=0;
    book[1]=1;
    
    //Dijkstra算法核心语句
    for(i=1;i<=n-1;i++)//循环n-1次,每次都找到一行中的最小值,也就是对应的最小的点。
    {
        min=inf;
        for(j=1;j<=n;j++)//找离某一点最近的点
        {
            if(book[j]==0 && dis[j]<min)
            {
                min=dis[j];
                u=j;
            }
        }
        book[u]=1;
        for(v=1;v<=n;v++)//找到最小点的最小距离的点,有的话就更新。
        {
            if(e[u][v]<inf)
            {
                if(dis[v]>dis[u]+e[u][v]) 
                    dis[v]=dis[u]+e[u][v];
            }
        }    
}

3.dijkstra    邻接表+优先级队列优化。
重载一个比较函数
struct node{  
    int x,d;  
    node(){}  
    node(int a,int b){x=a;d=b;}  
    bool operator < (const node & a) const  
    {  
        if(d==a.d) return x<a.x;  
        else return d > a.d;  
    }  
};  //定义一个结构体,重载比较函数

   
   
  1. vector<node> eg[Ni];  
  2. int dis[Ni],n;  
void Dijkstra(int s)  
{  
    int i;  
    for(i=0;i<=n;i++) dis[i]=INF;  
    dis[s]=0;  
    //用优先队列优化  
    priority_queue<node> q;  
    q.push(node(s,dis[s]));  
    while(!q.empty())  
    {  
        node x=q.top();q.pop();  
        for(i=0;i<eg[x.x].size();i++)  
        {  
            node y=eg[x.x][i];  
            if(dis[y.x]>x.d+y.d)  
            {  
                dis[y.x]=x.d+y.d;  
                q.push(node(y.x,dis[y.x]));  
            }  
        }  
    }  
}  

4.bellman-Ford
一:初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。二:进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。三:遍历途中所有的边(edge(u,v)),判断是否存在这样情况: d(v) > d (u) + w(u,v) 则返回false,表示途中存在从源点可达的权为负的回路。
struct node{
    int from,to,w;
};
node edge[100];
bool Ford()
{
    for(i = 1; i <= n; i ++)
        dis[i] = inf;
    dis[1] = 0;
    for(i = 1; i <= n; i ++)
    {
        flag = false;
        for(j = 1; j <= m; j ++)
        {
            x = edge[i].from ;
            y = edge[i].to ;
            z = edge[i].w ;
            if(dis[y] > dis[x] + z)
            {
                dis[y] = dis[x] + z;
                flag = true;
            }
        }
        if(!flag)
            break;
        //如果更新到n遍,还能够继续更新dis数组,说明存在负权环 
        if(flag&&i == n) 
            return false;//返回false表示这个图存在负权环 
    }
    return true;//返回true表示求最短路成功 
}
5.SPFA
 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值