zoukankan      html  css  js  c++  java
  • SPFA的优化

    【为什么要优化】

    关于SPFA,他死了(懂的都懂)

     

    进入正题。。。

    一般来说,我们有三种优化方法。

    SLF优化:

    SLF优化,即 Small Label First  策略,使用 双端队列 进行优化。

    一般可以优化15%~20%,在竞赛中比较常用。

    设从 u 扩展出了 v ,队列中队首元素为 k ,若 dis[ v ] < dis[ k ] ,则将 v 插入队首,否则插入队尾。

    注:队列为空时直接插入队尾。

     1 deque<int> q;
     2 
     3 inline void spfa(int x)
     4 {
     5     memset(d,0x3f,sizeof(d));
     6     memset(v,0,sizeof(v));
     7     d[x]=0;v[x]=1;
     8     q.push_back(x);
     9     while(q.size())
    10     {
    11         int index=q.front();q.pop_front();
    12         v[index]=0;
    13         for(int i=head[index];i;i=g[i].next){
    14             int y=g[i].ver,z=g[i].edge;
    15             if(d[y]>d[index]+z){
    16                 d[y]=d[index]+z;
    17                 if(!v[y]){
    18                     if(!q.empty()&&d[y]>=d[q.front()]) q.push_back(y);
    19                     else q.push_front(y);
    20                     v[y]=1;
    21                 }
    22             }
    23         }
    24     }
    25 }

    LLL优化:

    LLL优化,即 Large Label Last  策略,使用 双端队列 进行优化。

    一般用SLF+LLL可以优化50%左右,但是在竞赛中并不常用LLL优化。(所以我就懒得写了,这是从这个大佬那里嫖来的

    设队首元素为 k ,每次松弛时进行判断,队列中所有 dis 值的平均值为 x 。

    若 dist[ k ] > x ,则将 k 插入到队尾,查找下一元素,直到找到某一个 k 使得 dis[ k ] <= x ,则将 k 出队进行松弛操作。

     1 void spfa(){
     2     int u,v,num=0;
     3     long long x=0;
     4     list<int> q;
     5     for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
     6     path[s]=0;
     7     vis[s]=true;
     8     q.push_back(s);
     9     num++;
    10     while(!q.empty()){
    11         u=q.front();
    12         q.pop_front();
    13         num--;x-=path[u];
    14         while(num&&path[u]>x/num){
    15             q.push_back(u);
    16             u=q.front();
    17             q.pop_front();
    18         }
    19         vis[u]=false;
    20         for(int i=head[u];i;i=a[i].next){
    21             v=a[i].to;
    22             if(relax(u,v,a[i].w)&&!vis[v]){
    23                 vis[v]=true;
    24                 if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
    25                 else q.push_back(v);
    26                 num++;x+=path[v];
    27             }
    28         }
    29     }
    30     for(int i=1;i<=n;i++)printf("%d ",path[i]);
    31     printf("
    ");
    32 }

     

    DFS优化:

    这种优化顾名思义,就是用dfs的思想代替bfs的思想来优化Bellman-Ford。

    常常用于判断正/负环,时间复杂度可以达到O(m)(m是边)。思路是,我们每一次dfs的时候如果走回之前dfs过的点,那就是有环,除了这个dfs的标记,我们还可以打另一个vis数组记录更新过权值的节点,以后就不必重复更新,大大降低复杂度。

    不过如果无环的话,那还是上面那两种优化稍微适用一点。代码比较短,但是不好扩展。

     1 inline bool spfa(int x)
     2 {
     3     dfs[x]=1;
     4     for(int i=head[x];i;i=g[i].next)
     5     {
     6         int y=g[i].ver,z=g[i].edge;
     7         if(!v[y]||d[y]<d[x]+z){
     8             if(dfs[y]) return 0;
     9             v[y]=1;
    10             d[y]=d[x]+z;
    11             if(!spfa(y)) return 0;
    12         }
    13     }
    14     dfs[x]=0;
    15     return 1;
    16 }
  • 相关阅读:
    javascript创建对象的方法--基本模式
    javascript进阶课程--第二章--对象
    JavaScript中的global对象,window对象以及document对象的区别和联系
    onblur 对象失去焦点事件
    php排序
    php数组插入数据
    thinkphp多层volist实现多表查询
    数据转换
    循环赛日程安排问题
    JS中setTimeout()的使用方法具体解释
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11025087.html
Copyright © 2011-2022 走看看