• (模板)hdoj2544(最短路--bellman-ford算法&&spfa算法)


    题目链接:https://vjudge.net/problem/HDU-2544

    题意:给n个点,m条边,求点1到点n的最短路。

    思路:

      今天学了下bellman_ford,抄抄模板。dijkstra算法和该算法都是单源最短路径算法,但是dij不能适用含负权边的图。而bellman-ford算法适用于负权边,原理是进行n-1次松弛操作,每次都要对m条边进行松弛,所以算法复杂度是O(mn),比dijkstra要高。如果n-1次操作之后还能进行松弛,说明存在负环。

    AC code:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxn=105;
    const int maxm=10005;
    const int inf=0x3f3f3f3f;
    int n,m,dis[maxn],cnt,loop;
    
    struct node{
        int u,v,w;
    }edge[maxm<<1];
    
    void adde(int u,int v,int w){
        edge[++cnt].v=v;
        edge[cnt].u=u;
        edge[cnt].w=w;
    }
    
    void bellman_ford(int s){
        for(int i=1;i<=n;++i)
            dis[i]=inf;
        dis[s]=0;
        //n-1次松弛    
        for(int i=1;i<n;++i){
            bool ok=0;
            for(int j=1;j<=cnt;++j){
                int u=edge[j].u,v=edge[j].v,w=edge[j].w;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    ok=1;
                }
            }
            if(!ok) break;
        }
        //loop=1说明存在负环
        for(int i=1;i<=cnt;++i){
            int u=edge[i].u,v=edge[i].v,w=edge[i].w;
            if(dis[v]>dis[u]+w){
                loop=1;
                break;
            }
        }
    }
    
    int main(){
        while(scanf("%d%d",&n,&m),n||m){
            cnt=0,loop=0;
            for(int i=1;i<=m;++i){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                adde(u,v,w);
                adde(v,u,w);
            }
            bellman_ford(1);
            printf("%d
    ",dis[n]);
        }
        return 0;
    }

    思路2:

    spfa是bellman-ford的队列优化版本,使用条件一样,vis标记该点是否在队列中,被更新的结点如果不在队列中要重新入队。也可以用来求是否存在负环,用updcnt数组记录每个结点更新次数,如果==n说明更新了n次,即存在负环。

    然后说一下spfa的时间复杂度是O(km),k为常数,但最坏情况是O(mn),比较毒瘤,慎用!

    下面的代码是luoguP3385,判负环。

    AC code:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    const int maxn=2005;
    const int maxm=6005;
    const int inf=0x3f3f3f3f;
    int T,n,m,head[maxn],vis[maxn],cnt,upd[maxn],dis[maxn];
    
    struct node{
        int v,w,nex;
    }edge[maxm];
    
    void adde(int u,int v,int w){
        edge[++cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].nex=head[u];
        head[u]=cnt;
    }
    
    bool spfa(){
        for(int i=1;i<=n;++i)
            vis[i]=0,upd[i]=0,dis[i]=inf;
        queue<int> que;
        que.push(1);
        vis[1]=1,dis[1]=0,++upd[1];
        while(!que.empty()){
            int u=que.front();que.pop();
            vis[u]=0;
            for(int i=head[u];i;i=edge[i].nex){
                int v=edge[i].v,w=edge[i].w;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    if(!vis[v]){
                        ++upd[v];
                        if(upd[v]>n) return true;
                        vis[v]=1;
                        que.push(v);
                    }
                }
            }
        }
        return false;
    }
    
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i)
                head[i]=0;
            cnt=0;
            for(int i=1;i<=m;++i){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                if(w<0){
                    adde(u,v,w);
                }
                else{
                    adde(u,v,w);
                    adde(v,u,w);
                }
            }
            if(spfa()) printf("YE5
    ");
            else printf("N0
    ");
        }
        return 0;
    }

      拓展:

      bellman-ford算法还能用来求最长路或者是判断正环,只用改下松弛条件即可。改变dis数组的定义为从源点到其它结点最长路径的长度,初始化为0,松弛时,如果dis[v]<dis[u]+w,则更新,其它操作一样。入poj1860。

    AC code:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    const int maxn=205;
    int n,m,s,head[maxn],vis[maxn],upd[maxn],cnt;
    double V,dis[maxn];
    
    struct node{
        int v,nex;
        double r,c;
    }edge[maxn<<1];
    
    void adde(int u,int v,double r,double c){    
        edge[++cnt].v=v;
        edge[cnt].r=r;
        edge[cnt].c=c;
        edge[cnt].nex=head[u];
        head[u]=cnt;
    }
    
    bool spfa(int s,double V){
        for(int i=1;i<=n;++i) dis[i]=0,vis[i]=0,upd[i]=0;
        dis[s]=V,vis[s]=1;
        queue<int> que;
        que.push(s);
        ++upd[s];
        while(!que.empty()){
            int u=que.front();que.pop();
            vis[u]=0;
            for(int i=head[u];i;i=edge[i].nex){
                int v=edge[i].v;
                double r=edge[i].r,c=edge[i].c;
                if(dis[v]<(dis[u]-c)*r){
                    dis[v]=(dis[u]-c)*r;
                    if(!vis[v]){
                        ++upd[v];
                        if(upd[v]>n) return true;
                        que.push(v);
                        vis[v]=1;
                    }
                }
            }
        }
        if(dis[s]>V) return true;
        return false;
    }
    
    int main(){
        scanf("%d%d%d%lf",&n,&m,&s,&V);
        for(int i=1;i<=n;++i) head[i]=0;
        cnt=0;
        for(int i=1;i<=m;++i){
            int u,v;
            double ruv,cuv,rvu,cvu;
            scanf("%d%d%lf%lf%lf%lf",&u,&v,&ruv,&cuv,&rvu,&cvu);
            adde(u,v,ruv,cuv);
            adde(v,u,rvu,cvu);
        }
        if(spfa(s,V)) printf("YES
    ");
        else printf("NO
    ");
        return 0;
    }
  • 相关阅读:
    矩阵分析 p13~p20
    矩阵分析 p1~p13
    复变函数2
    口语80篇(1-2)
    复变函数1
    背单词方法
    writing practice
    将博客搬至CSDN
    windows内核编程 白话设备栈
    sfliter__except_handler4
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11849901.html
Copyright © 2020-2023  润新知