POJ 3259/ SOJ 2751: Wormholes

题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=2751


题目大意:

现在有一些无向边,走过每条边需要花费一定的时间ti。

另有一些有向的“虫洞”,钻过虫洞可以回到过去,让时间倒流ti。

问能否从某地出发,经过一定的虫洞和道路,在出发的时间之前回到原地。


算法:

我们不妨把道路看作正权边,

虫洞看作负权边,

以ti为权值建边。

不难看出,如果图上有负环,就可以实现在出发的时间之前回到原地。

SPFA寻找负环,只要在做最短路的时候判断是否存在某点的入队次数大于n即可。

因为没有负环的最短路,最多由n个点组成,

如果一个点被松弛了超过n次,那么必定是存在了负环。

另外,寻找负环的SPFA,可以用迭代深搜SPFA,详见姜碧野的《SPFA算法的优化及应用》,

如果像我一样比较懒,懒得改算法,那么用栈来代替FIFO队列保存顶点,也可以提高找负环的效率


需要注意的是,此题POJ上数据较弱,没有考虑图不连通的情况,请去SOJ测试。

其实考虑图不联通的情况也很简单,建一个虚拟起点,向每个点连一条边权为0的边,

当然在每个联通块做一次SPFA也是一样的,复杂度不变。


代码如下:

#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
int head[505],Q[505],inq[505],d[505],cot[505],E,flag;

struct
{
  int u,v,w,nxt;
} edge[6000];

void addedge(int u,int v,int w)
{
  edge[E].u=u;
  edge[E].v=v;
  edge[E].w=w;
  edge[E].nxt=head[u];
  head[u]=E++;
}

int main()
{
  int cas,n,m,k,u,v,w,front,rear;
  char c;
  while(~scanf("%d",&cas))
    {
      while(cas--)
        {
          scanf("%d%d%d",&n,&m,&k);
          memset(head,-1,sizeof(head));
          memset(d,INF,sizeof(d));
          memset(inq,0,sizeof(inq));
          memset(cot,0,sizeof(cot));
          E=0;
          flag=1;
          for(int i=1; i<=n; i++)
            {
              addedge(0,i,0);
            }
          while(m--)
            {
              scanf("%d%d%d",&u,&v,&w);
              addedge(u,v,w);
              addedge(v,u,w);
            }
          while(k--)
            {
              scanf("%d%d%d",&u,&v,&w);
              addedge(u,v,-w);
            }

          front=rear=0;
          Q[rear++]=0;
          inq[0]=1;
          d[0]=0;

          while(front!=rear)
            {
              u=Q[front++];
              front%=505;
              inq[u]=0;
              for(int i=head[u]; i!=-1; i=edge[i].nxt)
                {
                  v=edge[i].v;
                  if(d[v]>d[u]+edge[i].w)
                    {
                      d[v]=d[u]+edge[i].w;
                      if(!inq[v])
                        {
                          Q[rear++]=v;
                          rear%=505;
                          inq[v]=1;
                        }
                      cot[v]++;
                      if(cot[v]==n+1)
                        {
                          flag=0;
                          break;
                        }
                    }
                  if(!flag)
                    break;
                }
              if(!flag)
                break;
            }
          if(!flag)
            puts("YES");
          else
            puts("NO");
        }
    }
  return 0;
}



你可能感兴趣的:(POJ 3259/ SOJ 2751: Wormholes)