zoukankan      html  css  js  c++  java
  • 算法队列SPFA算法详解

    文章结束给大家来个程序员笑话:[M]

        处理存在负环的图的单源最短路径,bellman-ford算法是比拟经典的一个,但是大家都道知,这个算法的效率其实不咋的,因为它只道知要求单源最短路,至多做|v|(j图的点结数)次松懈作操,觉感有点目盲吧,这里分析一个有西南交通大学段凡丁1994年明发的一个算法即SPFA,很大程度上化优了bellman-ford算法(议建没有学过的,先去解了一下这个算法),算法的时光效率我就不说了,因为我得觉当我们悉熟某个算法后之,析分时光复杂度就没什么问题了,如果目盲的记忆,义意不大。

        SPFA算法的妙精的地方在于不是目盲的做松懈作操,而是用一个队列存保前当做了松懈作操的点结。只要队列不空,就能够续继从队列里头取点,做松懈作操,想一想bellman-ford算法吧,它只道知做|v|次循环就对了。上面讲讲SPFA为什么这样做呢?还是举个例子:

        算法和队列

        前当源点1在队列里头,于是我们取了1点结来做对图停止松懈作操,明显这个时候2,3点结的距离更新了,入了队列,我们假设他们没入队列,即在现队列经已空了,那么还有没有必要续继做松懈作操呢?明显没必要了啊,因为源点1要到其他点结必须经过2或3点结啊。在现懂了吧。

        先讲一下SPFA的大致想思

        算法大致流程是用一个队列来停止维护。 初始时将源入加队列。 每次从队列中掏出一个元素,并对有所与他相邻的点停止松懈,若某个相邻的点松懈胜利,如果该点没有在队列中,则将其入队。 直到队列为空时算法结束。

        断判无有负环:如果某个点进入队列的次数超越V次则存在负环(SPFA法无处置带负环的图)

        每日一道理
    生活中受伤难免,失败跌倒其实不可怕,可怕的是因此而一蹶不振,失去了对人生的追求与远大的理想。没有一个人的前进道路是平平稳稳的,就算是河中穿梭航行的船只也难免颠簸,生活中所遇上的坎坷磨难不是偶尔给予的为难,而是必然所经受的磨练。

        SPFA算法有两个化优算法 SLF 和 LLL: SLF:Small Label First 策略,设要入加的点节是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。 LLL:Large Label Last 策略,设队首元素为i,队列中有所dist值的平均值为x,若dist(i)>x则将i插入到队尾,找查下一元素,直到找到某一i使得dist(i)<=x,则将i出对停止松懈作操。 SLF 可以使速度进步 15 ~ 20%;SLF + LLL 可进步约 50%。 在际实的应用中SPFA的算法时光效率不是很定稳,为了免避坏最情况的涌现,平日应用效率更加定稳的Dijkstra算法。个人得觉LLL化优每次要求平均值,不太好,为了简略,我们可以之间用c++STL里头的优先队列来停止SLF化优

        上面贴一下用用优先队列来停止SLF化优代码

    #include <iostream>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int INF = 0x3fffffff;
    const int MAX = 100;
    int map[MAX][MAX];
    int dis[MAX];
    bool vis[MAX];
    int num[MAX];//录记每一个点结入队的次数
    struct cmp
    {
         bool operator()(int x,int y)
         {
              return x>y;
         }
    };
    bool SPFA(int s0,int n)
    {
         priority_queue<int,vector<int>,cmp> q;
         memset(vis,false,sizeof(vis));
         memset(num,0,sizeof(num));
         for(int i=0;i<n;i++)
              dis[i] = INF;
         dis[s0] = 0;
         q.push(s0);
         vis[s0] = true;
         num[s0]++;
         while(!q.empty())
         {
              int p = q.top();
              q.pop();
              for(int i=0;i<n;i++)
              {
                   if(dis[p]+map[p][i]<dis[i])
                   {
                        dis[i] = dis[p]+map[p][i];
                        if(!vis[i])
                        {
                             q.push(i);
                             num[i]++;
                             if(num[i]>n)//存在负环
                             {
                                  return false;
                             }
                             vis[i]=true;
                        }
                   }
              }
              vis[p] = false;
         }
         return true;
    }

        

        

    文章结束给大家分享下程序员的一些笑话语录: 某程序员对书法十分感兴趣,退休后决定在这方面有所建树。花重金购买了上等的文房四宝。一日突生雅兴,一番磨墨拟纸,并点上了上好的檀香,颇有王羲之风 范,又具颜真卿气势,定神片刻,泼墨挥毫,郑重地写下一行字:hello world.

  • 相关阅读:
    SVN打tag
    validate命令---rman进行备份和回复的验证
    通达OA 小飞鱼工作流在线培训教程(一)HTML基础介绍
    How to improve Java&#39;s I/O performance( 提升 java i/o 性能)
    mybatis批量插入、批量删除
    Java測试覆盖率工具----Cobertura,EclEmma
    Java Secret: Using an enum to build a State machine(Java秘术:用枚举构建一个状态机)
    灵活数据源的固定行列交叉报表的制作
    HDFS学习笔记(1)初探HDFS
    JPEG压缩图像超分辨率重建算法
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3065873.html
Copyright © 2011-2022 走看看