最短路总结

一,Dijkstra(迪杰斯特拉算法)

       Dijkstra算法是求解单源最短路问题的算法。(非负权边)

       Dijkstra提出,按各个顶点与源点之间路径长度的递增次序,生成源点到各个顶点的最短路径。

       也就是说,先找出距离源点最近的一条路径,再参照它找出距离源点次近的一条路径,以此类推,直到从源点到其他各顶点的最短路径全部找出。

       是一种贪心的思想。时间复杂度为n^2。

      

该算法仅适用于单源的非负权边的最短路问题。

如果存在负权边的话,就会出现错误。为什么?因为该算法是基于贪心思想的。如果存在负权会出现错误。

代码实现比较简单:

const int N=?;
const int INF=0xfffff
int map[N][N];
bool vis[N],dis[N],n;//用来区分

void Dijkstra(int s0){
    memset(vis,false,sizeof(vis));
    vis[s0]=true;
    for(int i=1;i<=n;i++)
    dis[i]=map[s0][i];
    //-----------------------------
    for(int i=1;i<=n;i++){
        int Bfind=s0,Dis=INF
        for(int j=1;j<=n;j++)
        if(!vis[j]&&dis[j]<Dis){
            Bfind=j;
            Dis=dis[j];
        }
        if(Bfind==s0) break;
        vis[Bfind]=true;
    //-------------------------------
        for(int j=1;j<=n;j++)
        if(!vis[j]&&dis[j]<dis[Bfind]+map[Bfind][j]){
            dis[j]=dis[Bfind]+map[Bfind][j];
        }
    //-------------------------------
    }
    printf("%d\n",dis[?]);
}

二,Bellman_ford(贝尔曼-福德算法)

        Bellman_ford算法是求解一般单源最短路的算法。(可能存在负边)

        算法操作就是,对图进行|V|-1次松弛操作,即可求出最短路径。

        可以看出Bellman_ford的时间复杂度为|V||E|。

        最重要的是理解什么是松弛操作:

     理解了什么是松弛操作了,理解起来就很容易了。

    为什么要进行|V|-1次松弛操作?

    因为,某点到源点的距离最短,最多通过|V|-1次松弛操作可以得到。

代码很好写:

const int N=?;
const int M=?;
const int INF=0xffffff;
struct Edge{
    int start,end;
    int value;
}edge[M];
int n,m,dis[N],path[N];

void Bellman_ford(){
    for(int i=1;i<=n;i++)
    dis[i]=INF;
    dis[startpoint]=0;
    for(int i=1;i<n;i++){
        for(int j=1;j<=m;j++){
            int st=edge[j].start;
            int en=edge[j].end;
            int va=edge[j].value;
            if(dis[en]>dis[st]+va){
                dis[en]=dis[st]+va;
                path[en]=st;
            }
        }
    }
}

如果存在负权回路,那么,那么就不存在最短路,以为,每次经过负权回路都会减小。

那么,怎么判断是否存在负权回路呢?如果存在负权回路,那么,在进行|V|次以后的松弛操作,还会变小。

所以,只需要在,做完松弛操作后,判断一下,再次做松弛操作时,会不会再次减小。

代码:(加到,松弛完以后)

bool Judge(){
    for(int i=1;i<=m;i++){
        int st=edge[j].start;
        int en=edge[j].end;
        int va=edge[j].value;
        if(dis[en]>dis[st]+va)
        return false;
    }
}

打印路径:

需要注意的是,打印路径的时候。需要注意的是,记录的是前驱,而非后继,为什么呢?

因为,一个点最短路径的前驱是唯一的,而后继可能有很多。

递归打印路径,自己写出来的竟然。自己递归还需努力。

int path[N]={'-1'};
int Print_Path(int step){
    if(path[step]==-1) return step;
    else Print_Path(path[one]);
    printf("%s%d",step==starstep?"":"->"?one);
}

今天的复习就到这里,明天继续。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值