• uva 558 Wormholes


    算是模板题,给定一个有向图,顶点从0到n-1编号,必须从0开始出发,问是否存在负环

    一开始写了一个Bellman-Ford,超时,然后就放弃了,写了个spfa的bfs版本,过了,然后又写了一个spfa的dfs版本,wa,然后改了一个下午,还是wa

    然后上网找了一下代码,发现很多人写的都是BF算法,看了一下自己的一样,怎么会超时呢??

    后来才发现,我读错题意了,我本来是理解为只要图中有负环就好了,所有枚举了所有的顶点作为源点去BF,所以才超时,现在是规定了0作为源点,所以就AC了

    然后就把spfa的dfs版本改了一下,不要枚举所有源点,规定0为源点,然后就AC了,再修改了一些细节地方,跑出了最好成绩0.008排名第5

    从这个地方可以看出,数据中,有的图是不连通的,所以有的连通分量有负环有的没有,如果枚举了所以的源点的话,有可能会WA

    但是有个地方比较困惑,我第一次写spfa的bfs版本的时候也是枚举了所有源点的,可以AC,照理来说应该是WA的,然后改为单源点后也是AC,是数据问题??不可能啊

    希望有人指点一下

    下面给出代码

    Bellman-Ford

    #include <cstdio>
    #include <cstring>
    #define N 1010
    #define M 2010
    #define INF 0x3f3f3f3f
    int d[N],u[M],v[M],w[M];
    int n,m;
    
    int BF(int s)  //Bellman-Ford
    {
        int k,i,j;
        for(i=0; i<n; i++) d[i]=INF;
        d[s]=0;
    
        for(k=1; k<n; k++)  //进行V-1次松弛
            for(int i=0; i<m; i++)  //枚举所有的边
            {
                int x=u[i],y=v[i];
                if( d[x]+w[i] < d[y] )
                    d[y]=d[x]+w[i];
            }
        int OK=1;
        for(int i=0; i<m; i++)  //检查一遍所有的边
        {
            int x=u[i],y=v[i];
            if( d[x]+w[i] < d[y] )  //还能进行松弛
            {
                OK=0;
                break;
            }
        }
    
        return OK;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=0; i<m; i++)
                scanf("%d%d%d",&u[i],&v[i],&w[i]);
            
            if(!BF(0))  //有负环
                printf("possible\n");
            else
                printf("not possible\n");
        }
        return 0;
    }

    SPFA_BFS

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define N 1010
    #define NN 5
    #define M 2010
    #define INF 0x3f3f3f3f
    int n,m;
    int d[N],f[N],nnext[M],u[M],v[M],w[M];  //用数组来模拟邻接表,并且使用头插法
    int c[N];  //记录每个顶点进队的次数
    bool vis[N];  //标记顶点在队内
    
    void input()
    {
        scanf("%d%d",&n,&m);
        memset(f,0,sizeof(f));
        //memset(nnext,0,sizeof(nnext));
    
        for(int i=1; i<=m; i++)  //边集数组从下标1保存到m
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            nnext[i]=f[u[i]];  //头插法
            f[u[i]]=i;        //头插法
        }
    /*
        printf("打印邻接表:\n");
        for(int i=0; i<n; i++)
        {
            printf("%d:\n",i);
            int j=f[i];
            while(j!=0)
            {
                printf("%d %d\n",v[j],w[j]);
                j=nnext[j];
            }
        }
    */
        return ;
    }
    
    int spfa_bfs(int s)
    {
        queue <int> q;
        memset(d,0x3f,sizeof(d));
        d[s]=0;
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
    
        q.push(s);  vis[s]=1; c[s]=1;
        //顶点入队vis要做标记,另外要统计顶点的入队次数
        int OK=1;
        while(!q.empty())
        {
            int x;
            x=q.front(); q.pop();  vis[x]=0;
            //队头元素出队,并且消除标记
            for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表
            {
                int y=v[k];
                if( d[x]+w[k] < d[y])
                {
                    d[y]=d[x]+w[k];  //松弛
                    if(!vis[y])  //顶点y不在队内
                    {
                        vis[y]=1;    //标记
                        c[y]++;      //统计次数
                        q.push(y);   //入队
                        if(c[y]>NN)  //超过入队次数上限,说明有负环
                            return OK=0;
                    }
                }
            }
        }
    
        return OK;
    
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            input();
            if(!spfa_bfs(0))  //有负环
                printf("possible\n");
            else
                printf("not possible\n");
        }
        return 0;
    }

    SPFA_DFS

    //时间最快0.008
    #include <cstdio>
    #include <cstring>
    #define N 1010
    #define M 2010
    #define INF 0x3f3f3f3f
    int d[N],f[N];
    bool vis[N];
    struct edge
    {
        int u,v,w,next;
    
    }e[M];
    int n,m;
    
    void input()
    {
        scanf("%d%d",&n,&m);
        memset(f,0,sizeof(f));
        for(int i=1; i<=m; i++)  //读入所有边
        {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            int u=e[i].u;
            e[i].next=f[u];
            f[u]=i;
        }
    /*
        printf("打印邻接表:\n");
        for(int i=0; i<n; i++)
        {
            printf("%d:\n",i);
            for(int k=f[i]; k!=0; k=e[k].next)
                printf("%d %d\n",e[i].v,e[i].w);
        }
    */
        return ;
    }
    
    int spfa_dfs(int u)
    {
        vis[u]=1;
        for(int k=f[u]; k!=0; k=e[k].next)
        {
            int v=e[k].v,w=e[k].w;
            if( d[u]+w < d[v] )
            {
                d[v]=d[u]+w;
                if(!vis[v])
                {
                    if(spfa_dfs(v))
                        return 1;
                }
                else
                    return 1;
            }
        }
        vis[u]=0;
        return 0;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            input();
            
            for(int i=0; i<n; i++)
            { vis[i]=0; d[i]=INF;}
            d[0]=0;
            
            if(spfa_dfs(0))  printf("possible\n");
            else     printf("not possible\n");
        }
        return 0;
    }    

    求指教  SPFA_BFS  枚举所有起点,按道理应该是WA的,为什么AC了…………

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define N 1010
    #define NN 5
    #define M 2010
    #define INF 0x3f3f3f3f
    int n,m;
    int d[N],f[N],nnext[M],u[M],v[M],w[M];  //用数组来模拟邻接表,并且使用头插法
    int c[N];  //记录每个顶点进队的次数
    bool vis[N];  //标记顶点在队内
    
    void input()
    {
        scanf("%d%d",&n,&m);
        memset(f,0,sizeof(f));
        //memset(nnext,0,sizeof(nnext));
    
        for(int i=1; i<=m; i++)  //边集数组从下标1保存到m
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            nnext[i]=f[u[i]];  //头插法
            f[u[i]]=i;        //头插法
        }
    /*
        printf("打印邻接表:\n");
        for(int i=0; i<n; i++)
        {
            printf("%d:\n",i);
            int j=f[i];
            while(j!=0)
            {
                printf("%d %d\n",v[j],w[j]);
                j=nnext[j];
            }
        }
    */
        return ;
    }
    
    int spfa_bfs(int s)
    {
        queue <int> q;
        memset(d,0x3f,sizeof(d));
        d[s]=0;
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
    
        q.push(s);  vis[s]=1; c[s]=1;
        //顶点入队vis要做标记,另外要统计顶点的入队次数
        int OK=1;
        while(!q.empty())
        {
            int x;
            x=q.front(); q.pop();  vis[x]=0;
            //队头元素出队,并且消除标记
            for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表
            {
                int y=v[k];
                if( d[x]+w[k] < d[y])
                {
                    d[y]=d[x]+w[k];  //松弛
                    if(!vis[y])  //顶点y不在队内
                    {
                        vis[y]=1;    //标记
                        c[y]++;      //统计次数
                        q.push(y);   //入队
                        if(c[y]>NN)  //超过入队次数上限,说明有负环
                            return OK=0;
                    }
                }
            }
        }
    
        return OK;
    
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            input();
            int s;
            for(s=0; s<n; s++)  //枚举所有源点
            {
                int tmp=spfa_bfs(s) ;
                //for(int i=0; i<n; i++)
                    //printf("%d ",d[i]);
                //printf("\n");
                if(!tmp)  break;
            }
            if(s<n)  //有负环
                printf("possible\n");
            else
                printf("not possible\n");
        }
        return 0;
    }
  • 相关阅读:
    方法转换IE、Firefox、Chrome区别
    splice方法便签
    webstorm主题网址+使用方法
    从程序员到项目经理(一):没有捷径
    界面原型图绘制工具Pencil
    程序员:伤不起的三十岁
    从程序员到项目经理(三):认识项目经理
    从程序员到项目经理(二):如何胜任
    原型制作软件 Axure RP
    软件界面原型设计工具 UIDesigner
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2786249.html
Copyright © 2020-2023  润新知