• Bellman_Ford+SPFA算法自用笔记


    一:Bellman_Ford

    1:Dijkstra并不能解决带有负权边的图。

    而Bellman_Ford算法可以。

    2:核心代码:

        for(int i=1;i<=n-1;i++)
        {
            for(int j=1;j<=m;j++)
            {
                dis[v[j]]=min(dis[v[j]],backup[u[j]]+w[j]);    
            }    
        }

    3:依然是熟悉的松弛操作,但这里是从部分扩大到全局。每次只松弛一部分。

    第1轮,得到从1号顶点"只能经过一条边"到达其余各顶点的最短路径长度。

    第2轮,得到从1号顶点"只能经过两条边"到达其余各顶点的最短路径长度。

    .......

    第k轮,就是"经过k条边"

    在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1条边

    所以最外层只需要循环n-1就可以了。

    注意:这里的前提是,此时无正负权回路,因为最短路径一定是一个不包含回路的简单路径。

    4:板子:

    有边数限制的最短路:https://www.cnblogs.com/liyexin/p/14025379.html

    判负环:https://www.cnblogs.com/liyexin/p/14026646.html

    二:SPFA

    1:对Bellman_Ford的优化版本。最坏情况下复杂度和Bellman-Ford 相同,为 O(VE)。

    Bellman_Ford中很多松弛操作都是没有必要。

    SPFA每次选取队首顶点u,对顶点u的所有出边进行松弛操作。其实思想就是,一个点被更新,那么它的邻居结点就有被更新的机会,所以可以把它们加入队列,没更新的点,自然没有机会进队列。

    记得引入判重操作,防止一个点在队列中同时出现多次。

    2:板子:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+10;
    const int inf=0x3f3f3f3f;
    int e[maxn],ne[maxn],h[maxn],idx,w[maxn];
    int dis[maxn],vis[maxn];
    int n,m;
    void init()
    {
        memset(h,-1,sizeof(h));
        memset(dis,inf,sizeof(dis));
        dis[1]=0;
    }
    void add(int a,int b,int c)
    {
        w[idx]=c;
        e[idx]=b;
        ne[idx]=h[a];
        h[a]=idx++;
    }
    int spfa()
    {
        queue<int>q;
        q.push(1);
        vis[1]=1;
        while(!q.empty())
        {
            int t=q.front();
            q.pop();
            vis[t]=0;
            for(int i=h[t];i!=-1;i=ne[i])
            {
                int j=e[i];
                if(dis[j]>dis[t]+w[i])
                {
                    dis[j]=dis[t]+w[i];
                    if(vis[j]==0)
                    {
                        q.push(j);
                    }
                }
            }
        }
        if(dis[n]>inf/2)
            return -1;
            return dis[n];
    }
    int main()
    {    
        init();
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(a,b,c);
        }
        int t=spfa();
        if(t==-1)
            cout<<"impossible"<<endl;
        else
            cout<<t<<endl;
    }
  • 相关阅读:
    nginx重启失败的解决方法
    Linux开机禁用开启防火墙
    Linux查看系统版本信息的几种方法
    Linux修改时区的正确方法
    Linux中awk的gsub函数用法
    Linux 的mktemp 命令详解
    tomcat的简单概要小结
    {面试题8: 旋转数组的最小数字}
    {面试题7: 使用两个队列实现一个栈}
    {面试题7: 用两个栈实现队列}
  • 原文地址:https://www.cnblogs.com/liyexin/p/14032444.html
Copyright © 2020-2023  润新知