图论(三) (一)最短路径问题 Bellman-Ford算法

简要:Bellman-Ford算法计算的仍然是从一个点到其他所有点的最短路径算法,其时间复杂度是O(NE),N表示点数,E表示边数,不难看出,当一个图稍微稠密一点,边的数量会超过点数那么实际上效率是低于Dijkstra算法的。但是本算法可以计算存在负权边的情况(不存在负回路),因此可以用于更广泛的情况,但其实在日常解题应用中我们基本不会用到该算法,因为有一个比它效率更高的算法即SPFA算法,下一章会介绍到。SPFA算法其实是从Bellman-Ford算法演变而来的,那么从基础的开始,我们先来理解一下Bellman-Ford算法。

算法描述:s为起点,dis[v]为s到v的最短距离,pre[v]是v的前驱结点,w[j]是边 j 的长度,j 边的起点和终点分别是u,v。

1、初始化:dis[s]=0, dis[v]=∞(v≠s), pre[s]=0

2、for(i=1;i<=n-1;i++)

for(j=1;j<=e;j++)

if(dis[u]+w[j]<dis[v]){

dis[v]=dis[u]+w[j];

pre[v]=u;

}

算法理解:一开始已标记的点只有起点,每一次枚举所有的边,总会有一些边连接着已标记的点和未标记的点,即已经计算过最短距离和为计算过最短距离的点。因此每次枚举都会更新一些未标记的点成为已标记的点。而n-1次则保证了最坏情况下所有的点均可以被标记,即图的样子是一“串”的情况。

对于负权回路的情况,因为每一次枚举都会走过一圈负权回路,那么恰好在该回路两边的点之间的最短距离就会无限减小,因此会造成错误。对此,大家给出了一个不是解决方法的解决方法,就是如果在两重循环结束后,再次枚举每条边,如果再次出现某两点的距离减少,那么就返回"错误",已表示有负权回路,无法算出答案。

当然,对于负权回路也有解决方法,在介绍完SPFA算法后会补充一下。

代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int n,e,s;
struct node{
    int x;
    int y;
    int val;
}m[105];
int dis[105],pre[105],a,b,w[105][105];
int bellmanford(int s){
     int i,j;

     for(i=1;i<=n;i++)
      dis[i]=w[s][i];
    dis[s]=0;pre[s]=0;
     for(i=1;i<=n-1;i++)
      for(j=1;j<=e;j++)
           if(dis[m[j].x]+m[j].val<dis[m[j].y])
           {
           dis[m[j].y]=dis[m[j].x]+m[j].val;
        pre[m[j].y]=m[j].x;
           }
     for(j=1;j<=e;j++){
         if(dis[m[j].x]+m[j].val<dis[m[j].y]) return 0;
     }
     return dis[5];

}
int main(){
    int i,j;
    scanf("%d%d",&n,&e);
    memset(dis,100,sizeof(dis));
    memset(w,100,sizeof(w));
     for(i=1;i<=e;i++){
        scanf("%d%d%d",&m[i].x,&m[i].y,&m[i].val);
        a=m[i].x;
        b=m[i].y;
        w[a][b]=m[i].val;
    }
    for(i=1;i<=5;i++)
     for(j=1;j<=5;j++)
      printf("%d ",w[i][j]);
    scanf("%d",&s);
    printf("%d",bellmanford(s));
    return 0;
} 

原文地址:https://www.cnblogs.com/uncklesam7/p/8878006.html

时间: 2024-10-19 07:57:45

图论(三) (一)最短路径问题 Bellman-Ford算法的相关文章

Bellman - Ford 算法解决最短路径问题

Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力不从心了,而Bellman - Ford算法可以解决这种问题. Bellman - Ford 算法可以处理路径权值为负数时的单源最短路径问题.设想可以从图中找到一个环路且这个环路中所有路径的权值之和为负.那么通过这个环路,环路中任意两点的最短路径就可以无穷小下去.如果不处理这个负环路,程序就会永远运

Bellman—Ford算法思想

---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G运行Bellman—Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路.若存在负权回路,单源点最短路径问题无解:若不存在这样的回路,算法将给出从源点s到图G的任意顶点v的最短路径值d[v] Bellman—Ford算法流程 分为三个阶段: (1)初始化:将除源点外的所有顶点

图论(三) (一)最短路径算法 2.Dijkstra算法

Dijkstra 算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值.该算法的时间复杂度是O(N2),相比于处理无负权的图时,比Bellmad-Ford算法效率更高. 算法描述: 首先引用<算法导论>中的一段比较官方的话,如果可以看懂,那下一部分就可以跳过了: "Dijkstra算法在运行过程中维持的关键信息是一组结点集合S.从源结点s到该集合中每个结点之间的最短路径已经被找到.算法重复从结点集 V - S 中算则最短路径估计的最小的结点 u ,将 u 加

最短路径——Bellman Ford算法(C++)

源代码: #include<cstdio>#include<cstring>int m(1),n,k,i[1001],x[1001],y[1001],f[1001];int main(){ scanf("%d%d",&n,&k); for (int a=1;a<=n;a++) for (int b=1;b<=n;b++) { scanf("%d",&i[m]); if (i[m]!=-1) { x[m]=a

poj 3259 Wormholes (BELLman—FOrd算法)(邻接矩阵表示)

http://poj.org/problem?id=3259 之前一开始 ,没做出来,搁置了好几天才看见bug所在.所以今天a掉了 ,把代码贴出来,这个使用邻接矩阵表示的 ,下一篇用邻接表可以提高效率. #include<iostream> #include<queue> #include<stdio.h> #include<string.h> using namespace std; const int INF=600; int G[INF][INF];

POJ 1860 Currency Exchange (Bellman ford)

Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22405   Accepted: 8095 Description Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and pe

bellman-ford算法

给定图G(V, E)(其中V.E分别为图G的顶点集与边集),源点s, 数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0: 以下操作循环执行至多n-1次,n为顶点数:对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v).w(u, v)为边e(u,v)的权值:若上述操作没有对Distant进行更新,说明最短路径已经查找完

图论(三)------广度优先搜索与单源无权最短路径

有一个无权的图G,使用某个顶点s作为输入参数,找出从s到其它顶点的最短路径.这样,只要计算包含在路径中的边数就可以了. 比如,一个word ladder problem,一次只变换一个字母,找出从fool到sage的最短路径. 可用的单词可以转化为一个图: 首先寻找与fool距离为1的顶点: 然后可以寻找距离fool为2的顶点: 最后,搜索出全部顶点: 这样搜索一个图的方法称为广度优先搜索:距开始点最近的那些顶点首先被搜索,最远的那些顶点最后被搜索. def unweighted(G,v): q

图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负. Dijkstra算法是贪婪算法的一个很好的例子.设置一顶点集合S,从源点s到集合中的顶点的最终最短路径的权值均已确定.算法反复选择具有最短路径估计的顶点u,并将u加入到S中,对u 的所有出边进行松弛.如果可以经过u来改进到顶点v的最短路径的话,就对顶点v的估计值进行更新. 如上图,u为源点,顶点全加入到优先队列中. ,队列中最小值为u(值为0),u出队列,对u的出边进行松弛(x.v.w),队列最小值