求无向图的 割点和桥 【模版】

在看这个之前,最好已经对有向图中tarjan算法求scc 有所理解

参考文章
(ps 本人较笨,看了许多文章才理解)
详解 点击传送门

传送门
传送门
传送门

代码 (手打不一定对)

一 求割点

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#define CLR(a,b) memset((a),(b),sizeof(a))
#define inf 0x3f3f3f3f
#define mod 100009
#define LL long long
#define MAXN  1000+10
#define MAXM 2000000+100 
#define ll o<<1
#define rr o<<1|1
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
using namespace std;
void read(int &x){
    x=0;char c;
    while((c=getchar())<'0');
    do x=x*10+c-'0';while((c=getchar())>='0');
}
struct Edge {
    int from,to,next;
}edge[MAXM];
int n,m;
int head[MAXN],top;  //向前星 
int low[MAXN],dfn[MAXN]; 
int dfs_clock;  //时间戳 
int iscut[MAXN]; //节点是不是割点 
int exist; //  图本身是不是联通着的 
void addedge(int a,int b)
{
    Edge e={a,b,head[a]};
    edge[top]=e; head[a]=top++;
}
void init()
{
    memset(head,-1,sizeof(head));
    top=0;
}
void getmap()
{
    int a,b; 
     while(m--)
     {
        cin>>a>>b;
        addedge(a,b);
        addedge(b,a);
      } 
}
void tarjan(int now,int pre)
{
    low[now]=dfn[now]=++dfs_clock;
    int son=0;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        Edge e=edge[i];
        if(!dfn[e.to])
        {
            son++;
            tarjan(e.to,now);
            low[now]=min(low[now],low[e.to]);
            if(low[e.to]>=dfn[now]&&pre!=-1)  
            { iscut[now]=1; }
        }

        else if(dfn[now]>dfn[e.to]&&pre!=e.to)  // 这个条件加不加都可以的 
        low[now]=min(low[now],dfn[e.to]);

    }

    if(pre==-1&&son<2) iscut[now]=0;
    if(pre==-1&&son>1) iscut[now]=1;   
}

void find_cut(int le,int ri)
{
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(iscut,0,sizeof(iscut));
    dfs_clock=0;exist=1;

    tarjan(le,-1);
    for(int i=le;i<=ri;i++)
    {
        if(!dfn[i]) 
        {
            tarjan(i,-1);
            exist=0;
        }
    }
}

int main()
{
    while(scanf("%d",&n)&&n)
    {
        init();
        getmap();
        find_cut(1,n);
        int ans=0; // 割点的个数 
        for(int i=1;i<=n;i++)
        if(iscut[i]) ans++;
        printf("%d\n",ans);
    }
    return 0;
}

第二 求桥
代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#define CLR(a,b) memset((a),(b),sizeof(a))
#define inf 0x3f3f3f3f
#define mod 100009
#define LL long long
#define MAXN  1000+10
#define MAXM 2000000+100 
#define ll o<<1
#define rr o<<1|1
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
using namespace std;
void read(int &x){
    x=0;char c;
    while((c=getchar())<'0');
    do x=x*10+c-'0';while((c=getchar())>='0');
}
struct Edge{
    int from,to,value,next,cut;
}edge[MAXM];
int head[MAXN],top;
int low[MAXN],dfn[MAXN];
int dfs_clock;
int n,m;
int exist; //  图本身不是连通的
void addedge(int a,int b,int c)
{
    Edge e={a,b,c,head[a],0};
    edge[top]=e;head[a]=top++;
}
void init()
{
    memset(head,-1,sizeof(head));
    top=0;
}
void getmap()
{
    int a,b,c;
    while(m--)
    {
        cin>>a>>b>>c;
        addedge(a,b,c);
        addedge(b,a,c);
    }
}
void tarjan(int now,int pre)
{
    low[now]=dfn[now]=++dfs_clock;
    int have=1;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        Edge e=edge[i];
        if(have&&e.to==pre) // 保留 重边 要是不想保留 直接 if(e.to==pre) continue;
        {
            have=0;
            continue;
        }
        if(!dfn[e.to])
        {
            tarjan(e.to,now);
            low[now]=min(low[now],low[e.to]);
            if(low[e.to]>dfn[now])
            {
                e.cut=1;
                edge[i^1].cut=1; //通过位运算找到反向边
            }

        } else  low[now]=min(low[now],dfn[e.to]);

    }
}
void find_bridge(int le,int ri)
{
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    dfs_clock=0;
    tarjan(le,-1);
    exist=1;
    for(int i=le;i<=ri;i++)
    {
        if(!dfn[i])
        {
            exist=0;
            tarjan(i,-1);
         } 
    }
}
int main()
{

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值