zoukankan      html  css  js  c++  java
  • spfa及其优化

    发现spfa居然也有优化,十分的震惊,现在由我细细道来(#^.^#)

    Description
        给你一个有向且边权全部非负的图,输出1到n的最短路。
    Input
        第一行两个自然数n(n<=100000)和m(m<=200000),表示点数和边数。接下来m行,每行3个数a,b,l,其中1<=a,b<=n,l<=1000。
    Output
        仅一个整数,为1到n的最短路。如果无解,输出-1。
    Sample Input
    10 10
    1 5 46
    1 10 50
    2 7 23
    3 4 40
    3 7 3
    3 9 21
    4 9 27
    5 8 45
    5 10 30
    7 10 15
    Sample Output
    50
    Hint
     如果是练SPFA,过90分就可以了(不过如果你的SPFA可以过完,在下拜你为师……)。

    这个出题人要拜我为师o(* ̄︶ ̄*)o

    我们会想一下bell——ford如何进化到spfa.

    SPFA对Bellman-Ford算法优化的关键之处在于意识到:只有那些在前一遍松弛中改变了距离估计值的点,才可能引起他们的邻接点的距离估计值的改变。因此,算法大致流程是用一个队列来进行维护,即用一个先进先出的队列来存放被成功松弛的顶点。初始时,源点s入队。当队列不为空时,取出队首顶点, 对它的邻接点进行松弛。如果某个邻接点松弛成功,且该邻接点不在队列中,则将其入队。经过有限次的松弛操作后,队列将为空,算法结束。SPFA算法的实现,需要用到一个先进先出的队列queue 和一个指示顶点是否在队列中的标记数组mark。为了方便查找某个顶点的邻接点,图采用邻接表存储。

    这样,我们的加入队列的顺序是随机的,现在,让我们看看两个优化。

    一个叫做SLF,一个叫做LLL,先%一下

    SLF又称Small Label First 策略. (比较常用)

    比较当前点和队首元素,如果小于队首,则插入队首,否则加入队尾

    这个优化有什么道理呢,我想是这样的

    1.每次加入了边后,都要对可以到达的点松弛,如果先加入队列的元素足够小,那么他的更新效果更加彻底,下一次碰到与这个点相连的点,这个点就很大概率不会入队了,这样就可以减少运算了

    嘿嘿(#^.^#)

    而LLL又称LLL: Large Label Last 策略. (不太常用)

    设队首元素为i,每次弹出时进行判断,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出对进行松弛操作。

    据说一些数据卡LLL可以卡到指数级只不过LLL还是挺好的(以后还是LLL少用)

    发一个SLF优化的代码

    #include<bits/stdc++.h>
    
    using namespace  std;
    
    const int maxn=100000+10;
    
    const int INF=0x7FFFFFFF;
    
    int pre[maxn];
    
    int dis[maxn];
    
    int path[maxn];
    
    bool vis[maxn];
    
    int head[maxn];
    int n,m;
    
    int tot,cnt;
    struct node
    {
        int v,w,next;
    }E[2*maxn];
    void add(int u,int v,int w)
    {
    
        E[tot].v=v;
    
        E[tot].w=w;
    
        E[tot].next=head[u];
    
        head[u]=tot++;
    
    }
     void init()
    
    {
    
        tot=0;
    
        memset(vis,false,sizeof((vis)));
    
        memset(head,-1,sizeof(head));
    
    }
    
    void spfa(int st)
    
    {
    
        for(int i=1;i<=n;i++)
            vis[i]=false,dis[i]=INF;
        int now,next;
        dis[st]=0;
        vis[st]=true;
        deque<int>q;
        q.push_back(st);
        pre[st]=-1;
        while(!q.empty())
        {
            now=q.front();
            q.pop_front();
            vis[now]=false;
            for(int i=head[now];i!=-1;i=E[i].next)
            {
                next=E[i].v;
                if(dis[next]>dis[now]+E[i].w)
                {
                    dis[next]=dis[now]+E[i].w;
                    pre[next]=now;
                     if(!vis[next])
                     {
                          vis[next]=true ; 
                         if( q.empty()||dis[next]>dis[q.front()]) q.push_back(next);
                             else q.push_front(next);
                    }
                }
    
            }
    
        }
    
    }
    void print(int x)
    {
        if(pre[x]==-1) return;
        print(pre[x]);
        printf("%d ",x);
    }
    int main()
    
    {
            init();
            scanf("%d%d",&n,&m);
                  // int st,en;
    //        scanf("%d%d",&st,&en);
            int u,v,w;
            for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);add(u,v,w);}
            spfa(1);
            if(dis[n]==INF)
            {printf("-1");return 0;}
            printf("%d
    ",dis[n]);
            //printf("%d ",st);
            //print(en);
    
            printf("
    ");
    
        
        return 0;
    }

     不知道为什么加了两个优化以后又T了,莫名其妙(我以后不用LLL了)╭(╯^╰)╮;

    #include<bits/stdc++.h>
    
    using namespace  std;
    
    const int maxn=100000+10;
    
    const int INF=0x7FFFFFFF;
    
    int pre[maxn];
    
    int dis[maxn];
    
    int path[maxn];
    
    bool vis[maxn];
    
    int head[maxn];
    int n,m;
    
    int tot,cnt;
    struct node
    {
        int v,w,next;
    }E[2*maxn];
    void add(int u,int v,int w)
    {
    
        E[tot].v=v;
    
        E[tot].w=w;
    
        E[tot].next=head[u];
    
        head[u]=tot++;
    
    }
     void init()
    
    {
    
        tot=0;
    
        memset(vis,false,sizeof((vis)));
    
        memset(head,-1,sizeof(head));
    
    }
    
    void spfa(int st)
    
    {
    
        for(int i=1;i<=n;i++)
            vis[i]=false,dis[i]=INF;
        int now,next;
        dis[st]=0;
        vis[st]=true;
        deque<int>q;
        q.push_back(st);
        pre[st]=-1;int tot=1;
        int sum=0;
        while(!q.empty())
        {
            now=q.front();
            q.pop_front();
            vis[now]=false;
            tot--; sum-=dis[now] ;
            for(int i = head[now];i != -1;i = E[i].next)
            {
                next = E[i].v;
                if(dis[next]>dis[now]+E[i].w)
                {
                    dis[next]=dis[now]+E[i].w;
                    pre[next]=now;
                     if(!vis[next])
                     {
                          vis[next]=true ; 
                         if( q.empty()||dis[next]>dis[q.front()]||dis[next] * tot <= sum) q.push_back(next);
                             else q.push_front(next);
                         tot++;sum+=dis[next];    
                    }
                }
    
            }
    
        }
    
    }
    void print(int x)
    {
        if(pre[x]==-1) return;
        print(pre[x]);
        printf("%d ",x);
    }
    int main()
    
    {
            init();
            scanf("%d%d",&n,&m);
                  // int st,en;
    //        scanf("%d%d",&st,&en);
            int u,v,w;
            for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);add(u,v,w);}
            spfa(1);
            if(dis[n]==INF)
            {printf("-1");return 0;}
            printf("%d
    ",dis[n]);
            //printf("%d ",st);
            //print(en);
    
            printf("
    ");
    
        
        return 0;
    }
  • 相关阅读:
    过桥问题
    修改state中数组对象某一个字段(state中某个属性为对象或数组时,需要修改该对象中的某一个属性)
    git 如何提交,新建, 拉取远程分支,git基本操作,git新手教学
    el-image组件大图预览不能定位当前图片的处理
    vue数组遍历动态渲染到页面
    vue路由传参的三基本方式
    git push时报错:error: failed to push some refs to/hint: Updates were rejected because the tip of your current branch is behind/hint: its remote counterpart. Integrate the remote changes
    时间格式转换/时间戳的转换
    Day.js :一个轻量的处理时间和日期的 JavaScript 库
    node多版本管理(node版本切换、node版本更新及降低版本)
  • 原文地址:https://www.cnblogs.com/star-eternal/p/7602474.html
Copyright © 2011-2022 走看看