判环
有向图
如果只有正(负)边权的图,拓扑即可,如果存在点没有入队,那么一定是存在环的。也可以用 tarjan,如果存在一个 scc 不是单独的一个点,那么就有环。
/* Case1: topo */
bool check(){
for(int i=1;i<=n;i++)
if(!in[i]) Q.push(i);
while(!Q.empty()){
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=e[i].next)
if(!(--in[e[i].to])) Q.push(e[i].to);
}
for(int i=1;i<=n;i++)
if(in[i]) return 1;
return 0;
}
否则的话考虑 SPFA,建一个超级源点,可以一次性判环。
inline bool SPFA(){
for(int i=1;i<=n;i++)
add(n+1,i,0),dis[i]=inf;
dis[n+1]=0; Q.push(n+1);
while(!Q.empty()){
int u=Q.front(); Q.pop(); vis[u]=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].dis){
dis[v]=dis[u]+e[i].dis;
in[v]=in[u]+1;
if(in[v]>n) return 1;
if(!vis[v]) vis[v]=1,Q.push(v);
}
}
}
return 0;
}
无向图
考虑 dfs ,如果遇到返祖边则检查一下当前记录的 dis[u]+e[i].dis 是否为负(正),即可判断。
基环树
注意内向树和外向树有点小区别实现的时候需要注意。
void dfs(int u){
static bool tag=0;
sta[++top]=u;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa[u]) continue;
if(ins[v]){
tag=1; int y;
do{
imp[y=sta[top--]]=1;
a[++m]=y;
}while(y!=v);
return ;
}
ins[u]=1,fa[v]=u,dfs(v),ins[u]=0;
if(tag) return ;
}
top--;
}