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;

}

  

你可能感兴趣的:(orm)