zoukankan      html  css  js  c++  java
  • Wormholes(虫洞)

    poj3259

    题目大意:给出一个F代表农场的个数,其实就是测试样例组数,给出个N代表每个农场包含N个厂区,M代表N个厂区之间之间的路径条数,W表示有W个虫洞

    题目上说路径是双向的,虫洞是单向的,意味着是有向图,并且说虫洞从一个顶点到另一个顶点让时间倒流,意味着路的权值是负值,接下来的M行是路径的条数,并且题目已经说明是一个厂区到另一个厂区不一定只有一条路(Two fields might be connected by more than one path.),接下来的W行是虫洞的起始和结束位置,还有让时间倒退的值。

    解决:首先是建图,我用邻接矩阵,建图的时候要注意两个厂区之间不一定只有一条路,要添加一条语句让最小的进图,M个是双向的,W个是单向的,单向的不用判断直接赋值肯定没有比

    它的值还小的。然后是找负回路用的是 spfa

    #include <iostream>
    #include <queue>
    #include <cstring>
    using namespace std;
    const int N=3000;
    const int MAX=0x3f3f3f3f;
    int cost[N][N];
    int inq[N];
    int dist[N];
    int n,m,w;
    int cnt[N];
    bool spfa(int v)
    {
        int i;
        memset(dist,0x3f3f,sizeof(dist));
        memset(inq,0,sizeof(inq));
        memset(cnt,0,sizeof(cnt));
        int v0=v;
        dist[v0]=0;
        queue<int> q;
        q.push(v0);
        inq[v0]=1;
        // 源点进队列与不进队列虽然关系不大,但是进队列可以缩短运行时间,每进一次可是不要小看,
      //这个点面对的是所有的边,所以进队列要将cnt的值置为1
        cnt[v0]=1;
        while(!q.empty())
        {
            v0=q.front();
            q.pop();
            inq[v0]=0;
            for(i=1;i<=n;i++)
            {
                if(cost[v0][i]<MAX && dist[v0]+cost[v0][i]<dist[i])
                {
                    dist[i]=dist[v0]+cost[v0][i];
                    if(!inq[i])
                    {
                        inq[i]=1;
                        q.push(i);
                        //共有n条边,等于结点总数返回,大于当然可以,但是何必呢。费时不是
                        if(++cnt[i]==n)return true;
                    }
                }
            }
        }
        return false;
    }
    int main()
    {
        int icase,i,a,b,val;
        scanf("%d",&icase);
        while(icase--)
        {
            memset(cost,0x3f3f,sizeof(cost));
            scanf("%d%d%d",&n,&m,&w);
            for(i=0;i<m;i++)
            {//输入时比较一下,由于邻接矩阵两个顶点只能放一条边,只好选最短边放了
                scanf("%d%d%d",&a,&b,&val);
                if(cost[a][b]>val){cost[a][b]=cost[b][a]=val;}
            }
            for(i=0;i<w;i++)
            {//这个地方也是可以判断一下,选最短的边放,万一两个厂区之间有两个洞呢
                scanf("%d%d%d",&a,&b,&val);
                cost[a][b]=-val;
            }//自己假设的1是源点,若是不连通,就惨了,
            if(spfa(1)){puts("YES");}
             else puts("NO");
        } 
        system("pause");
        return 0;
    }
    

      虽然ac了,但是感觉漏洞百出,只是数据通过了,不只是为了通过数据,就万事大吉了。

    #include <queue>
    #include <cstring>
    const int MAX=0x3f3f3f3f;
    using namespace std;
    const int N=3000;
    int cost[N][N];
    int inq[N];
    int dist[N];
    int n,m,w;
    int cnt[N];
    bool spfa()
    {
        int i;
        memset(dist,0,sizeof(dist));
        memset(inq,0,sizeof(inq));
        memset(cnt,0,sizeof(cnt));
        int v0;
      //为了防止图不连通。将所有顶点入队,并且初始化dist为0,意味着
     //虚拟源点到各个顶点的距离为0
       queue<int> q;
        for(int i=1;i<=n;i++)q.push(i);//虽然进队,但是不能cnt[i]++,
        while(!q.empty())
        {
            v0=q.front();
            q.pop();
            inq[v0]=0;
            for(i=1;i<=n;i++)
            {
                if(cost[v0][i]<MAX && dist[v0]+cost[v0][i]<dist[i])
                {
                    dist[i]=dist[v0]+cost[v0][i];
                    if(!inq[i])
                    {
                        inq[i]=1;
                        q.push(i);//判断的时候还要是n,虚拟的无视
                        if(++cnt[i]==n)return true;
                    }
                }
            }
        }
        return false;
    }
    int main()
    {
        int icase,i,a,b,val;
        scanf("%d",&icase);
        while(icase--)
        {
            memset(cost,0x3f3f,sizeof(cost));
            scanf("%d%d%d",&n,&m,&w);
            for(i=0;i<m;i++)
            {
                scanf("%d%d%d",&a,&b,&val);
                if(cost[a][b]>val){cost[a][b]=cost[b][a]=val;}
            }
            for(i=0;i<w;i++)
            {
                scanf("%d%d%d",&a,&b,&val);
                cost[a][b]=-val;
            }
            if(spfa()){puts("YES");}
             else puts("NO");
        } 
        system("pause");
        return 0;
    }
                   
    

     以上的程序虽然都可以但是时间复杂度已经达到了1500ms,以下用spfa+邻接表实现。

    #include <iostream>
    #include <queue>
    #include <cstdio>
    using namespace std;
    const int N=510;
    struct node
    {
        int v,w,next;
    };
    node e[50000];
    int n,m,w,ss,ee,t;
    int pos;
    int head[N];
    int cnt[N];
    int dist[N];
    bool inq[N];
    void init()
    {
             memset(head,-1,sizeof(head));
             memset(dist,0,sizeof(dist));
             memset(cnt,0,sizeof(cnt));
             memset(inq,0,sizeof(inq));
    }
    void addedge(int u,int v,int w)
    {
        e[pos].v=v;
        e[pos].w=w;
        e[pos].next=head[u];
        head[u]=pos++;
    }
    bool spfa()
    {
         int v0,v,w,i;
        queue<int> q;//虚拟顶点各个顶点入队
        for(i=1;i<=n;i++)q.push(i);
        while(!q.empty())
        {
            v0=q.front();
            q.pop();
            inq[v0]=false;
            for(i=head[v0];i!=-1;i=e[i].next)
            {
                v=e[i].v;
                w=e[i].w;
                if(dist[v0]+w<dist[v])
                {
                    dist[v]=dist[v0]+w;
                    if(!inq[v])
                    {
                        inq[v]=1;
                        q.push(v);
                        if(++cnt[v]==n)return true;
                    }
                }
            }
        }
        return false;
    }
    int main()
    {
        int i,f;
        scanf("%d",&f);
        while(f--)
        {
            pos=0;
          
            scanf("%d%d%d",&n,&m,&w); 
            init();//就因为init放在了scanf前面导致不断错误,并提出了可笑的问题
            for(i=0;i<m;i++) 
            {
                scanf("%d%d%d",&ss,&ee,&t);
                addedge(ss,ee,t);
                addedge(ee,ss,t);
            }
            for(i=0;i<w;i++)
            {
                scanf("%d%d%d",&ss,&ee,&t);
                addedge(ss,ee,-t);
            }
            if( spfa() )puts("YES");
            else puts("NO");
        }
        system("pause");
        return 0;
    }
    

      

  • 相关阅读:
    2018-6-2_《JS操作数组(纯洁方法)》
    Centos7 xfs分区格式化挂载
    centos 常用命令集锦
    docker1.12在cento7里的组建swarm (一)
    centos7线程、文件打开数等调优日志(非优化案例、仅仅是个个人记录、为把相关配置文件记录一下)
    Centos7.2 新镜像、系统到手 更新清理 并且安装docker1.2以后版本 目前内容适合docker 1.7.x ce(社区版)
    程序员新手 0年份等级 指导(一) 开发人员IT架构总览
    docker 土法制作zookeeper镜像 并且搭建集群 基于centos7.2
    centos 删除多余的内核启动项
    docker1.12在cento7里的组件swarm (二)
  • 原文地址:https://www.cnblogs.com/hpustudent/p/2147569.html
Copyright © 2011-2022 走看看