tarjan解决割点和桥

本文介绍了如何利用Tarjan算法在无向图中检测割点和桥。割点是指删除该点导致图不连通的顶点,而桥则是删除后使得图不连通的边。通过深度优先搜索(DFS)和dfn、low值的计算,可以判断割点和桥。当low[v]>=dfn[u]时,u为割点;若low[v]>dfn[u],则u到v的边是桥。文章提到了在洛谷平台上的相关题目,并分享了未缩点和缩点后的AC代码,以及红书的解决方案。
摘要由CSDN通过智能技术生成

对于某个无向图

割点又称割顶,如果删掉这个点,图不连通,那么这个点就是一个割点

、如果删掉这个边,图不连通,那么这个边就是一个桥

 

1、对于根节点,如果有一个以上子树,那么就是割点

2、对于非根节点,dfn[u]表示时间戳,即dfs到第几次访问到u点,

low[u]表示顶点u及其子树中的点,通过非父子边(回边,即dfs树多出来的边),能够回溯到的最早的点(dfn最小)的dfn值

(但不能通过连接u与其父节点的边)。对于边(u, v),如果low[v]>=dfn[u],此时u就是割点。

 

桥:low[v]>dfn[u]则          u到v(v到u)   是  桥

模板、割点、洛谷p3388

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
struct node{int val,next;}E[(int)1e6+7];
int n,m,x,y,tot,cnt = 1,ans,head[maxn],low[maxn],dfn[maxn];
bool vis[maxn];
void add(int u,int v){E[cnt] = {v,head[u]},head[u] = cnt++;}
void tarjan(int u,int Fa,int cnt = 0){
    low[u] = dfn[u] = ++tot;
    for(int i=head[u];i;i = E[i].next){
        int v = E[i].val;
        if(!dfn[v]){
            tarjan(v,u),low[u] = min(low[u],low[v]);
            if(u == Fa)cnt++;
            if(low[v]>=dfn[u] && u != Fa)vis[u] = true;//割点
            //if(low[v]>dfn[u]) 桥 u->v || v->u
        }else if(dfn[v]<dfn[u] && v != Fa)//单纯的求割点的话这个elseif可以不写
            low[u] = min(low[u],dfn[v]);
    }
    if(cnt>=2 && u==Fa)vis[u] = true;
}
signed main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,i);
    for(int i=1;i<=n;i++)if(vis[i])ans++;
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)if(vis[i])printf("%d ",i);
    return 0;
}

红书代码、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值