• 最短路


    Bellman-Ford
    最短路中一定不含环(因为含有负环的最短路不存在,零环和正环可以除去),所以从起点到终点的最短路经过的边数不超过(n-1),所以一定可以通过(n-1)轮松弛得到最短路,每一轮松弛用所有边进行更新
    如果第(n)次松弛依然有起点到某个顶点的最短路被更新,说明从起点可以到达一个负环,最短路不存在
    可以增加一个优化,如果在某轮松弛中起点到任何顶点的最短路都没有被更新,那么不需要进行下一轮松弛,直接退出
    时间复杂度(O(nm)),其中(n)为点数,(m)为边数

    const int inf=0x3f,maxn=110,maxm=10010;
    int n,m,dis[maxn];
    
    struct Edge{
        int u,v,w;
    }edge[maxm];
    
    void Bellman_Ford(int s){
        memset(dis,0x3f,sizeof(dis));
        dis[s]=0;
        int check;
        for(int i=1;i<=n;i++){
            check=0;
            for(int j=1;j<=m;j++){
                int u=edge[j].u,v=edge[j].v,w=edge[j].w;
                if(dis[v]>dis[u]+w){
                    dis[v]=min(dis[v],dis[u]+w);
                    check=1;
                }
            }
            if(!check) break;
        }
    }
    

    SPFA
    SPFA是经过队列优化的Bellman-Ford算法,在Bellman-Ford的某轮松弛中,如果起点到某个顶点的距离没有被更新,那么在下一轮中,就不需要从这个顶点出发去松弛其他顶点了
    所以通过一个先进先出的队列来保存松弛过的顶点,每次取出队首顶点(u),并且枚举从(u)出发的所有边((u, v)),如果(dis[u]+w(u,v)<dis[v]),则更新(dis[v]),然后判断顶点(v)是否已经在队列中,如果不在就将顶点(v)插入队尾。这样不断从队列中取出队首顶点来进行松弛操作,直至队列为空
    任意顶点被更新的次数一定小于(n),如果某个顶点第(n)次被更新,则说明从起点到终点的路径中存在负环
    SPFA算法在最坏的情况下,时间复杂度和Bellman-Ford算法一样,为(O(nm))。但是一般不会达到这个上界,一般的期望时间复杂度为(O(km)),其中(k)为常数

    const int inf=0x3f3f3f3f;
    int dis[maxn];
    bool inq[maxn];
    queue<int> q;
    
    void spfa(int s){
        for(int i=1;i<=n;i++){
            dis[i]=(i==s)?0:inf;
            inq[i]=(i==s);
        }
        q.push(s);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            inq[u]=false;
            for(int i=head[u];~i;i=nxt[i]){
                int v=to[i];
                int w=weight[i];
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    if(!inq[v]){
                        q.push(v);
                        inq[v]=true;
                    }
                }
            }
        }
    }
    

    Dijkstra
    Dijkstra算法每次从最短距离已经确定的顶点开始松弛,最短距离已经确定的点就是当前(dis[i])最小的点
    如果如中存在负边权,则无法确定某个顶点是否已经取到最短距离,所以Dijkstra算法无法处理含有负边权的图
    每次通过遍历所有顶点找到(dis[i])最小的顶点,时间复杂度(O(n^2))

    const int maxn=110,inf=0x3f3f3f3f;
    int dis[maxn],book[maxn];
    
    void Dijkstra(int s){
        for(int i=1;i<=n;i++) dis[i]=(i==s)?0:inf;
        memset(book,0,sizeof(book));
        book[s]=1;
        for(int i=head[s];~i;i=nxt[i]){
            int v=to[i],w=weight[i];
            dis[v]=min(dis[v],dis[s]+w);
        }
        for(int k=1;k<n;k++){
            int m=inf,id;
            for(int i=1;i<=n;i++){
                if(!book[i]){
                    if(m>dis[i]){
                        m=dis[i];
                        id=i;
                    }
                }
            }
            book[id]=1;
            for(int i=head[id];~i;i=nxt[i]){
                int v=to[i],w=weight[i];
                dis[v]=min(dis[v],dis[id]+w);
            }
        }
    }
    

    Dijkstra堆优化
    在查找(dis[i])最小的顶点时,可以使用优先队列优化
    由于队列中的点有可能重复,插入操作的上限是(m)次,所以队列中最多有(m)个点,时间复杂度(O((n+m)log m))

    const int maxn=110,inf=0x3f3f3f3f;
    int dis[maxn],book[maxn];
    
    void Dijkstra(int s){
        memset(dis,0x3f,sizeof(dis));
        dis[s]=0;
        memset(book,0,sizeof(book));
        priority_queue<PII> pq;
        pq.push({0,s});
        while(!pq.empty()){
            PII p=pq.top();
            pq.pop();
            int u=p.second;
            if(book[u]) continue;
            book[u]=1;
            for(int i=head[u];~i;i=nxt[i]){
                int v=to[i];
                int w=weight[i];
                if(book[v]) continue;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    pq.push({-dis[v],v});
                }
            }
        }
    }
    

    floyd
    计算任意两点间的最短路,基于动态规划,设(dis[k][i][j])表示只允许经过([1,k])中转的情况下,(i)(j)之间的最短路。所以有两种情况:
    1.如果最短路经过(k),则(dis[k][i][j]=dis[k-1][i][k]+dis[k-1][k][j])
    2.如果最短路不经过(k),则(dis[k][i][j]=dis[k-1][i][j])
    于是有状态转移方程:(dis[k][i][j]=min(dis[k-1][i][j],dis[k-1][i][k]+dis[k-1][k][j]))
    时间复杂度(O(n^3)),滚动数组优化之后,空间复杂度(O(n^2))

    const int maxn=110;
    int dis[maxn][maxn];
    
    void floyd(){
        for(int k=1;k<=n;k++){
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    if(i==j || i==k || k==j) continue;
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
                }
            }
        }
    }
    
  • 相关阅读:
    Python 3.4 .py文件打包成exe可执行文件方法
    windows找不到证书来让您登陆到网络,启用IEEE 802.1X验证为灰色
    重装系统之后电脑配置步骤
    win7(x64)matlab2010a 编译器安装
    用Interface Builder自定义UITableViewCell
    ASIHTTPRequest类库简介和使用说明
    IOS NSURL基本操作
    arc下asihttprequest等应用实现
    WampServer的配置
    javascript带范围的随机整数生成22
  • 原文地址:https://www.cnblogs.com/fxq1304/p/13550507.html
Copyright © 2020-2023  润新知