基环树

只有两种情况:

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);
    }