只有两种情况:
1.图连通的话 存在唯一环。
2.不连通 可能存在多个环。
无向图dfs求环,不能建双向边。
有向图 dfs求环,且可以求环的长度,(拓扑后单向边)且长度为2的环:
void dfs(int u,int d){
vis[u]=1,dep[u]=d;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to;
if(!vis[v]) dfs(v,d+1);
else if(vis[v]==1) b[++id]=dep[u]-dep[v]+1;
}vis[u]=2;
}
无向图找环,且不考虑两个点的环。因为如果是两个点就是重边了,所以一般环的长度至少为3。
void dfs(int u,int fa){
vis[u]=1;
for(int i=h[u];i;i=e[i].nt){
if(v==fa) continue;
if(!vis[v]) dfs(v,u);
else{
//为环长度>2的环。
}
}
}
还可以用并查集找环,当此时要连的边 f i n d ( u ) = f i n d ( v ) find(u)=find(v) find(u)=find(v),说明形成了一个环。
基环树用于dp的解法 就是断开环上的一条边,然后进行树形dp。
基环外向树(有向连边):环内无点,每个 i i i的入度为1。
基环内向树:环外无点,每个 i i i的出度为 1 1 1。
一般使用基环外向树, 若题目给定每个点 i i i的关系,可以通过不断求fa找环。
while(!vis[f[u]]){
u=f[u];
vis[u]=1;
}
dfs 求环WA点较多,用并查集建双向边,然后dfs(int u,int fa)比较方便,可以判二元环。
void dfs(int u,int fa){
f[u][1]=p[u],f[u][0]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
f[u][1]+=f[v][0];
f[u][0]+=max(f[v][0],f[v][1]);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)fa[i]=i;
for(int u=1,v;u<=n;u++){
scanf("%d%d",&p[u],&v);
if(find(u)==find(v)){
S[++cnt]=u,T[cnt]=v;
continue;
}
add(u,v);
add(v,u);
fa[find(u)]=find(v);
}