无向图找环

1.用记录深度的方法

void dfs(int u,int s){
	d[u]=s;
	for(int i=h[u];i;i=e[i].nt){
		int v=e[i].to;
		if(d[v]){	//如果有深度说明之前访问过,可能存在环.
			ans=max(ans,d[v]-d[u]+1);
		}
		else dfs(v,s+1); 
	}
}

如果 v v v u u u的前驱结点的话不受影响,因为 d [ v ] + 1 = d [ u ] d[v]+1=d[u] d[v]+1=d[u]

所以 d [ v ] − d [ u ] + 1 = − 1 + 1 = 0 d[v]-d[u]+1=-1+1=0 d[v]d[u]+1=1+1=0,对 a n s ans ans无影响。

该方法只能记录简单环的最大长度。

例题是 P O J 3985 POJ3985 POJ3985

对于下面这种图

无向图找环_Nginx

该方法得到的 a n s = 6 ans=6 ans=6,也就是 1 − 4 − 3 − 5 − 2 − 6 1-4-3-5-2-6 143526 这个环。

如果尝试用这种方法记录环的个数的话,可能会出现问题。

void dfs(int u,int s){
	d[u]=s;
	for(int i=h[u];i;i=e[i].nt){
		int v=e[i].to;
		if(d[v]){
			int len=d[v]-d[u]+1;
			//printf("(%d,%d) %d\n",u,v,len);
			if(len>2) num++;
			ans=max(ans,len);
		}
		else dfs(v,s+1); 
	}
}

还是上图, n u m = 2 num=2 num=2

因为此时 d f s dfs dfs的顺序是: 1 − 4 − 3 − 5 − 2 − 6 1-4-3-5-2-6 143526

只会在访问 e d g e ( 1 , 5 ) , e d g e ( 1 , 6 ) edge(1,5),edge(1,6) edge(1,5),edge(1,6) 时产生贡献。

因此会漏掉 1 − 5 − 2 − 6 1-5-2-6 1526 这个环。


2.记录深度+标记的方法。

void dfs(int u,int s){
	d[u]=s,vis[u]=1;
	for(int i=h[u];i;i=e[i].nt){
		int v=e[i].to;
		if(!vis[v]) dfs(v,s+1);
		else if(vis[v]==1){
			int len=d[u]-d[v]+1;
			if(len>2) num++;
			ans=max(ans,d[u]-d[v]+1);
		}
	}vis[u]=2;
}

与方法一实质一样,都只能统计简单环。唯一区别是它会把先搜索完的结点标记为2不可再搜。