luoguP3385 【模板】负环(dfs_Bellman)

来源:互联网 发布:亿维雅 知乎 编辑:程序博客网 时间:2024/06/06 03:35

题目链接

分析:
这道题如题面所说,普通的算法会T
一般Bellman的思想是:
采用广度优先,每当我们扩展出一个新的节点,总是把它放到队列的末尾,其缺点是中断了迭代的连续性
而实际上如果采用深度优先的思想,我们可以直接从这个新节点继续往下扩展
于是算法的实现方式可以改成不断从新节点往下递归进行求解
而对于负环的判断则显得更为简单,因为假如存在负环a1->a2->….ak->a1,那么算法运行时,会从某个点a1开始Dfs,最后又回到了这个点
所以只需用一个辅助数组记录当前节点是否在递归栈中便可及时检测出负环

tip

由于这是Bellman的变种,所以每次遍历完一个点,ta的入栈情况要修改成未入栈(和Bellman一样)

注意输出格式

//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;const int N=200005;const int mod=5000000;struct node{    int x,y,v,nxt;};node way[N<<1];int st[N],tot=0;int dis[N],n,m;bool in[N],ff;void add(int u,int w,int z){    tot++;    way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;}//int Bellman()//{//    queue<int> Q;//  memset(cnt,0,sizeof(cnt));//  memset(in,0,sizeof(in));//  for (int i=1;i<=n;i++)//  {//      dis[i]=0;//      Q.push(i);//      in[i]=1;//  } //  while (!Q.empty())//  {//      int now=Q.front(); Q.pop();//      in[now]=0;//      for (int i=st[now];i;i=way[i].nxt)//          if (dis[way[i].y]>dis[now]+way[i].v)//          {//              dis[way[i].y]=dis[now]+way[i].v;//              if (!in[way[i].y])//              {//                  in[way[i].y]=1;//                  Q.push(way[i].y);//                  if (++cnt[way[i].y]>n) return 1;//              }//          }//  }//  return 0;//}void Bellman(int now){    if (ff) return;                     //存在环     in[now]=1;    for (int i=st[now];i;i=way[i].nxt)        if (dis[way[i].y]>dis[now]+way[i].v&&ff==0)        {            dis[way[i].y]=dis[now]+way[i].v;            if (in[way[i].y])            {                ff=1; return;            }             else Bellman(way[i].y);        }    in[now]=0;                         //入栈状态     return;}int main(){    int T;    scanf("%d",&T);    while (T--)    {        memset(st,0,sizeof(st));        tot=0;        scanf("%d%d",&n,&m);        for (int i=1;i<=m;i++)        {            int u,w,z;            scanf("%d%d%d",&u,&w,&z);            add(u,w,z);            if (z>=0) add(w,u,z);        }        memset(in,0,sizeof(in));             //访问记录         memset(dis,0,sizeof(dis));           //最短路         ff=0;        for (int i=1;i<=n;i++)        {            Bellman(i);            if (ff) break;        }        if (ff) printf("YE5\n");        //输出有毒         else printf("N0\n");    }    return 0;}