• 关于最短路的几个算法


    关于最短路的几个算法有Dijkstra,Bellman-Ford,Floyd

    Dijkstra:

    Dijkstra适用于边权为正的情况,从单个源点出发,到其他所有结点的最短路

    算法的核心是用已经知道的结点 i 的距离 d[i] 去更新和这个结点相连的其他结点的距离

    struct node
    {
        int d,u; //d是距离,u是另一个结点的编号
        bool operator<(const node A) const
        {
            return d>A.d;
        }
    };
    struct Dijkstra
    {
        int n,m;  //点数和边数
        vector<Edge> edges;  //边列表
        vector<int> G[MAXN];  //每个结点出发的边编号(从0开始编号)
        int vis[MAXN];  //判断点是否被访问
        int d[MAXN];  //s到各个点的距离
        int p[MAXN];  //最短路上的一条边
    
        void init(int n)
        {
            this->=n;
            for(int i=0;i<n;i++) G[i].clear();  //清空邻接表
            edges.clear();  //清空边表
        }
    
        void  AddEdge(int from,int to,int dist)  //如果是无向边需调用两次AddEdge
        {
            edges.push_back((Edge){from,to,dist});
            m=edges.size();
            G[from].push_back(m-1);
        }
    };
    void dijkstra(int s)  //求s到所有点的距离
    {
        priority_queue<node> Q;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
            d[i]=INF;
        d[s]=0;
        node start;
        start.d=0,start.u=s;
        Q.push(start);
        while(!Q.empty())
        {
            node x=Q.top;Q.pop();
            int u=x.u;
            if(vis[u]) continue;
            vis[u]=1;
            for(itn i=0;i<G[u].size();i++)
            {
                Edge& e=edges[G[u][i]];
                if(d[e.to]>d[u]+e.dis)
                {
                    node next;
                    d[e.to]=d[u]+e.dis;
                    p[e.to]=G[u][i];
                    next.d=d[e.to];
                    next.u=e.to;
                    Q.push(next);
                }
            }
        }
    }

    其核心思想还是没有变,依旧是用已经知道的点去更新起点s到其他点的距离,用优先队列,优先级最大的是距离最小的点,然后用这个点去更新其他点

    最坏的情况下仍然会循环n-1次,但是从整体上看,每条边恰好被检查过一次,所以松弛操作的执行次数恰好是m次,这样只用找未被访问的d的最小值即可

    可以说即使是稠密图,用了priority_queue还是会比用邻接矩阵的Dijstra算法快,因为不满足d[e.to]>d[u]+e.dis是不能入队的,所有push操作会很少

    Bellman-Ford:

    Bellman-Ford也是一个求最短路的算法,这个算法用于算最短路的时候,如果最短路存在,那么一定是一个不含环的最短路,那么这个算法还有一个用处就是判环,

    如果存在负环的话,那么便不会存在最短路(因为会不断松弛下去)

    如果不含环的话,那么最多便通过n-1个结点(不包含起点),通过n-1“轮”松弛操作便可以计算出最短路

    算法核心就是通过循环n-1次,每次对所有的边进行松弛操作边去更新结点距离

    for(int i=1;i<=n;i++)
        d[i]=INF;
    d[0]=0;
    for(int i=0;i<n-1;i++)  //迭代n-1次
    {
        for(int j=0;j<m;j++)  //检查每一条边
        {
            int x=u[i],y=v[i];
            if(d[x]<INF)
            {
                d[y]=min(d[y],d[x]+w[i]);  //松弛操作
            }
        }
    }

    这个代码很明显没有进行负环的判定,复杂度是O(nm)

    可以用FIFO队列进行优化,可以进行循环检查

    struct Edge
    {
        int from,to,dis;
        Edge(int u,int v,int d):from(u),to(v),dis(d) {}
    };
    vector<Edge> edges;
    vector<int> G[MAXN];
    int vis[MAXN];  //判断结点是否被访问
    int p[MAXN];  //最短路上的一条弧
    int d[MAXN]; //起点s到各点的距离
    
    bool Bellman-Ford(int s)
    {
        queue<int> Q;
        memset(inq,0,sizeof(inq));
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<n;i++)
            d[i]=INF;
        d[s]=0;
        inq[s]=true;
        Q.push(s);
    
        while(!Q.empty())
        {
            int u=Q.front();Q.pop();
            inq[u]=false;
            for(int i=0;i<G[u].size();i++)
            {
                Edge& e=edges(G[u][i]);
                if(d[u]<INF && d[e.to]>d[u]+e.dis) //松弛
                {
                    d[e.to]=d[u]+e.dis;
                    p[e.to]=G[u][i];
                    if(!inq[e.to])
                    {
                        Q.push(e.to);
                        inq[e.to]=true;
                        if(++cnt[e.to]>n) return false;  //如果一个点入队大于n次,那么一定存在负环
                    }
                }
            }
            return true;
        }
    }

    用队列优化的Bellman-Ford也叫SPFA(Shortest Path Faster Algorithm)

    下面讨论下SPFA

     先转载这两篇,觉得写的不错,以后慢慢填坑

    http://blog.csdn.net/hqd_acm/article/details/5442872

    http://blog.csdn.net/hqd_acm/article/details/5804345

  • 相关阅读:
    关于mvvm模式中消息传递的疑问
    使用C#开发Metro 风格应用的路线图 触屏操作
    使用C#开发Metro 风格应用的路线图 metro设计原则
    使用C#开发Metro 风格应用的路线图 添加启动画面
    使用C#开发Metro 风格应用的路线图 在页面间导航、传值
    使用C#开发Metro 风格应用的路线图 移植wp7应用到metro上
    使用C#开发Metro 风格应用的路线图 metro应用生命周期的处理
    使用C#开发Metro 风格应用的路线图 控件分类介绍
    Entity Framework 4.1/4.3 之三(由4.0过渡到4.1/4.3) jerry
    Entity Framework 4.1/4.3 之六 (DBContext 之 3 状态跟踪 ) jerry
  • 原文地址:https://www.cnblogs.com/clliff/p/4681424.html
Copyright © 2020-2023  润新知