zoukankan      html  css  js  c++  java
  • [旧版][知识点]SPFA算法

    // 此博文为迁移而来,写于2015年4月9日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vx93.html

    Update - 20200608

    该博文内容现已更新并迁移至:

    [知识点] 8.5 最短路 https://www.cnblogs.com/jinkun113/p/13063162.html

    1、前言
           最短路算法有很多种,类似于Floyd和Dijkstra都是很早之前就学了的。其实每种最短路算法有各自的优势。Floyd适合于跑完全图,但是效率太慢(O(n3))。Dijkstra适合于跑没有负权的图,效率为O(n2)。而今天介绍的SPFA算法,是有一位中国人——段凡丁所提出来的(其实我很想吐个槽。。为什么人家弗洛伊德大叔提出了算法就叫弗洛伊德算法,迪杰斯特拉大爷提出的东西就叫迪杰斯特拉算法,段凡丁提出来的算法就变成了什么鬼SPFA(Shortest Path Faster Algorithm)。。严重的歧视啊。。。)
           其实SPFA没什么要讲的。看了一下模板就瞬间懂了。
           
    2、概念
           SPFA算法,是队列实现的Bellman-Ford算法。非常好理解,都知道BFS跑无权迷宫吧?其实SPFA可以直接理解为BFS跑有权图。因为它的形式和BFS太像了。大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛(松弛的意思自行脑补吧,看了程序就懂了),若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。先上代码:
     
    //代码更新于20160916
    #include <cstdio>
    #include <cstring>
    
    #define MAXN 10000
    #define MAXM 100000
    #define INF 0x3f3f3f3f 
    
    int T, n, m, u, v, w;
    int h[MAXN], q[MAXN], o, dis[MAXN], vis[MAXN], s, t;
    
    struct Edge {
        int v, next, w;
    } edge[MAXM * 2];
    
    void addEdge(int u, int v, int w) {
        edge[++o] = (Edge) {v, h[u], w}, h[u] = o;
    }
    
    int SPFA(int s, int t) {
        int head = 1, tail = 2;
        while (head != tail) {
            int o = q[head];
            for (int x = h[o]; x; x = edge[x].next) {
                int v = edge[x].v;
                if (dis[o] + edge[x].w < dis[v]) {
                    dis[v] = dis[o] + edge[x].w;
                    if (!vis[v]) q[tail++] = v, vis[v] = 1;
                }
            }
            vis[o] = 0;
            head++;
        }
        return dis[t];
    }
    
    int main() {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d %d %d", &u, &v, &w);
            addEdge(u, v, w), addEdge(v, u, w);
        }
        scanf("%d", &T);
        for (int i = 1; i <= T; i++) {
            memset(vis, 0, sizeof(vis)), memset(dis, INF, sizeof(dis));
            scanf("%d %d", &s, &t);
            dis[s] = 0, vis[s] = 1, q[1] = s;
            printf("%d", SPFA(s, t));
        }
        return 0;
    }
           初始化:设dis[i]代表目前源点到i点的最短距离,开始时dist全部为INF(无穷大),只有dis[s]=0。
           SPFA:维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个点s。用一个vis[i]记录i点是否处在队列中。每次迭代,取出队头的点v,依次枚举从v出发的边v->u,设边的长度为len,判断dis[v]+len是否小于dis[u],若小于则改进dis[u],并且由于s到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在队列中,就将它放入队尾。这样一直迭代下去直到队列变空,也就是s到所有点的最短距离都确定下来,结束算法。
           备注:SPFA还有一个很强大的功能,可以判负权环。若一个点入队次数超过n,则有负权环。
  • 相关阅读:
    发一注册表监控驱动代码
    Nikto
    在c#使用IOCP(完成端口)的简单示例
    C#中ref和out的使用小结
    Powerful x86/x64 Mini HookEngine
    C语言写的多线程下载器
    快速排序算法c#
    拓扑排序
    Dijkstra算法
    SRM 550 DIV2
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4678909.html
Copyright © 2011-2022 走看看