tarjan 连通性

tarjan处理强连通分量

利用tarjan处理,处理过程中每次遇到 dfn[rt]==low[rt],即为一个强连通块。获取color数组。

每个不同的color即表示该点属于第几个强连通分量。

vector<int> vec[maxn];
int tot;
int dfn[maxn],low[maxn];
bool vis[maxn];
int color[maxn],cnum;
void init()
{
    tot=0,cnum=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(color,0,sizeof(color));
}
stack<int> sta;
void tarjan(int rt)
{
    dfn[rt]=low[rt]=++tot;
    vis[rt]=1;sta.push(rt);
    int s=vec[rt].size();
    for(int i=0;i<s;i++)
    {
        int to=vec[rt][i];
        if(dfn[to]==0)
        {
            tarjan(to);
            low[rt]=min(low[rt],low[to]);
        }
        else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
    }
    if(dfn[rt]==low[rt])
    {
        cnum++;
        while(true)
        {
            int to=sta.top();sta.pop();
            color[to]=cnum;      //处理强连通分量color数组
            vis[to]=0;
            if(to==rt)break;
        }
    }
}

tarjan 缩点

利用强连通分量处理,得到每个点属于的前联通分量存在color中,再通过color数组进行需要的重建图或者其他运算,可以不需要重新建图,只需要利用color进行映射即可。

割点中,有向图和无向图没有区别,都要转化成无向图

割点

1.如果是头节点有大于等于1个子节点,那么他就是割点。

2.如果满足low[v]>=dfn[fa[v]],那么这个点的父节点 也就是fa[v]就是割点。

先用tarjan处理出low和dfn数组,再根据上面两个规则得到割点

vector<int> vec[maxn];
int tot;
int dfn[maxn],low[maxn];
bool vis[maxn];
int f[maxn];
void init()
{
    tot=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
}
stack<int> sta;
void tarjan(int rt,int fa)
{
    dfn[rt]=low[rt]=++tot;
    vis[rt]=1;sta.push(rt);
    f[rt]=fa;
    int s=vec[rt].size();
    for(int i=0;i<s;i++)
    {
        int to=vec[rt][i];
        if(to==fa) continue;
        if(dfn[to]==0)
        {
            tarjan(to,rt);
            low[rt]=min(low[rt],low[to]);
        }
        else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
    }
    if(dfn[rt]==low[rt])
    {
        while(true)
        {
            int to=sta.top();sta.pop();
            vis[to]=0;
            if(to==rt)break;
        }
    }
}

int n;
bool cut[maxn];
void getCutPoint()//rt儿子多于1个则为割点,其他点连通序大于其父时间序则父亲是割点
{
    init();
    tarjan(1,-1);
    memset(cut,0,sizeof(cut));
    int rtson=0;
    for(int i=2;i<=n;i++)
    {
        int fa=f[i];
        if(fa==1) rtson++;
        else if(dfn[fa]<=low[i]) cut[fa]=true;
    }
    if(rtson>1) cut[1]=true;
}

也可以直接在tarjan最后处理,这样可以不需要fa数组

vector<int> vec[maxn];
int tot;
int dfn[maxn],low[maxn];
bool vis[maxn];
bool cut[maxn];
void init()
{
    tot=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(cut,0,sizeof(cut));
}
stack<int> sta;
void tarjan(int rt,int fa)
{
    dfn[rt]=low[rt]=++tot;
    vis[rt]=1;sta.push(rt);
    int s=vec[rt].size();
    int son=0;
    for(int i=0;i<s;i++)
    {
        int to=vec[rt][i];
        if(to==fa) continue;
        if(dfn[to]==0)
        {
            son++;
            tarjan(to,rt);
            low[rt]=min(low[rt],low[to]);
        }
        else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
    }

    if(dfn[rt]==low[rt])
    {
        while(true)
        {
            int to=sta.top();sta.pop();
            vis[to]=0;
            if(to==rt)break;
        }
    }
    if(rt==1)    //处理割点
    {
        if(son>1) cut[rt]=true;
        else cut[rt]=false;
    }
    else if(dfn[fa]<=low[rt]) cut[fa]=true;
}

习题: poj 3717

割边

1.如果满足low[v]>dfn[fa[v]],那么这个点和父亲结点之间的边就是割边。

2.我们也很容易知道,对于一个连通图来说,tarjan缩点后是一个DAG,因此桥的数量等于染色数cnum-1.

先用tarjan处理出low和dfn数组,再根据上面规则1得到割边(下面代码是规则1的)

割边连接两个点,故需要一个bridge结构体

struct bridge   //桥结构体
{
    int x,y;
};
bool operator < (bridge a,bridge b)
{
    if(a.x==b.x)return a.y<b.y;
    return a.x<b.x;
}
bridge b[maxn];

vector<int> vec[maxn];
int tot;
int dfn[maxn],low[maxn];
bool vis[maxn];
int f[maxn];
void init()
{
    tot=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
}
stack<int> sta;
void tarjan(int rt,int fa)
{
    dfn[rt]=low[rt]=++tot;
    vis[rt]=1;sta.push(rt);
    f[rt]=fa;
    int s=vec[rt].size();
    int fc=0;
    for(int i=0;i<s;i++)
    {
        int to=vec[rt][i];
        if(to==fa && fc==0)
        {
            fc++;
            continue;
        }
        if(dfn[to]==0)
        {
            tarjan(to,rt);
            low[rt]=min(low[rt],low[to]);
        }
        else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
    }
    if(dfn[rt]==low[rt])
    {
        while(true)
        {
            int to=sta.top();sta.pop();
            vis[to]=0;
            if(to==rt)break;
        }
    }
    if(fc>1 && low[rt]>dfn[fa]) low[rt]=dfn[fa]; //重边不算桥,利用桥的判定条件简化判重
}

int n;
int ans;
void getBridge()
{
    init();
    for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i,-1);
    ans=0;
    for(int i=1;i<=n;i++)
    {
        int fa=f[i];
        if(fa!=-1 && dfn[fa]<low[i])
        {
            ans++;
            b[ans].x=i;b[ans].y=fa;
        }
    }
}

也可以直接在tarjan中获取桥信息,节约fa数组

struct bridge   //桥结构体
{
    int x,y;
};
bool operator < (bridge a,bridge b)
{
    if(a.x==b.x)return a.y<b.y;
    return a.x<b.x;
}
int ans;
bridge b[maxn];

vector<int> vec[maxn];
int tot;
int dfn[maxn],low[maxn];
bool vis[maxn];
void init()
{
    ans=0;tot=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
}
stack<int> sta;
void tarjan(int rt,int fa)
{
    dfn[rt]=low[rt]=++tot;
    vis[rt]=1;sta.push(rt);
    int s=vec[rt].size();
    int fc=0;    //记录是否和父亲之间存在重边
    for(int i=0;i<s;i++)
    {
        int to=vec[rt][i];
        if(to==fa && fc==0)
        {
            fc++;
            continue;
        }
        if(dfn[to]==0)
        {
            tarjan(to,rt);
            low[rt]=min(low[rt],low[to]);
        }
        else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
    }
    if(dfn[rt]==low[rt])
    {
        while(true)
        {
            int to=sta.top();sta.pop();
            vis[to]=0;
            if(to==rt)break;
        }
    }
    if(fc>1 && low[rt]>dfn[fa]) low[rt]=dfn[fa];//重边不算桥,利用桥的判定条件简化判重
    if(fa!=-1 && dfn[fa]<low[rt])     //判断该点和父亲结点之间能否存在割边
    {
        ans++;
        b[ans].x=rt;b[ans].y=fa;
    }
}

规则2:

struct node
{
    int x,y;
    bool friend operator < (node A,node B)
    {
        if(A.x == B.x)
            return A.y < B.y;
        return A.x < B.x;
    }
}bridge[maxn];

vector<int> vec[maxn];
int tot;
int dfn[maxn],low[maxn];
bool vis[maxn];
int color[maxn],cnum;
void init()
{
    tot=0,cnum=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(color,0,sizeof(color));
}
stack<int> sta;
void tarjan(int rt,int fa)
{
    dfn[rt]=low[rt]=++tot;
    vis[rt]=1;sta.push(rt);
    int s=vec[rt].size();
    int fc=0;
    for(int i=0;i<s;i++)
    {
        int to=vec[rt][i];
        if(to==fa &&fc==0)
        {
            fc++;
            continue;
        }
        if(dfn[to]==0)
        {
            tarjan(to,rt);
            low[rt]=min(low[rt],low[to]);
        }
        else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
    }
    if(dfn[rt]==low[rt])
    {
        cnum++;
        while(true)
        {
            int to=sta.top();sta.pop();
            color[to]=cnum;      //处理强连通分量color数组
            vis[to]=0;
            if(to==rt)break;
        }
    }
}

int n;
int ans;
void getBridge()
{
    init();
    for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i,-1);
    ans=0;
    for(int i=1;i<=n;i++)
    {
        int s=vec[i].size();
        for(int j=0;j<s;j++)
        {
            int to=vec[i][j];
            if(color[i]!=color[to] && i<to)
            {
                ans++;
                bridge[ans].x=i;
                bridge[ans].y=to;
            }
        }
    }
    sort(bridge+1,bridge+ans+1);
}

 

总Tarjan类

int n;
vector<int> vec[maxn];
struct Tarjan
{
    int tot;
    int dfn[maxn],low[maxn],f[maxn];
    bool vis[maxn];
    int color[maxn],cnum;
    void init()
    {
        tot=0,cnum=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(vis,0,sizeof(vis));
        memset(color,0,sizeof(color));
    }
    stack<int> sta;
    void tarjan(int rt,int fa)
    {
        dfn[rt]=low[rt]=++tot;
        vis[rt]=1;sta.push(rt);
        f[rt]=fa;
        int s=vec[rt].size(),fc=0;   //去重边
        for(int i=0;i<s;i++)
        {
            int to=vec[rt][i];
            if(to==fa && fc==0){fc++;continue;}
            if(dfn[to]==0)
            {
                tarjan(to,rt);
                low[rt]=min(low[rt],low[to]);
            }
            else if(vis[to]==1)low[rt]=min(low[rt],dfn[to]);
        }
        if(dfn[rt]==low[rt])
        {
            cnum++;
            while(true)
            {
                int to=sta.top();sta.pop();
                color[to]=cnum;      //处理强连通分量color数组
                vis[to]=0;
                if(to==rt)break;
            }
        }
    }

    bool cut[maxn];
    bool root[maxn];
    int son[maxn];
    void getCutPoint()//rt儿子多于1个则为割点,其他点连通序大于其父时间序则父亲是割点
    {
        init();
        memset(cut,0,sizeof(cut));
        memset(root,0,sizeof(root));
        memset(son,0,sizeof(son));
        for(int i=1;i<=n;i++)if(dfn[i]==0){root[i]=true;tarjan(i,-1);};
        for(int i=1;i<=n;i++)
        {
            int fa=f[i];
            if(fa==-1)continue;
            if(root[fa]==true) son[fa]++;
            else if(dfn[fa]<=low[i]) cut[fa]=true;
        }
        for(int i=1;i<=n;i++)if(root[i]==true && son[i]>1) cut[i]=true;
    }

    struct bridge   //桥结构体
    {
        int x,y;
        bool friend operator < (bridge a,bridge b)
        {
            if(a.x==b.x)return a.y<b.y;
            return a.x<b.x;
        }
    }b[maxn];
    int bnum;
    void getBridge()
    {
        init();
        for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i,-1);
        bnum=0;
        for(int i=1;i<=n;i++)
        {
            int s=vec[i].size();
            for(int j=0;j<s;j++)
            {
                int to=vec[i][j];
                if(color[i]!=color[to] && i<to)
                {
                    bnum++;
                    b[bnum].x=i;b[bnum].y=to;
                }
            }
        }
    }
}tj;

 

tarjan中统计缩点后出入度

int dup[maxn],dum[maxn];
for(int i=1;i<=n;i++)
{
    int cnow=color[i];
    int s=vec[i].size();
    for(int j=0;j<s;j++)
    {
        int to=vec[i][j];
        int cto=color[to];
        if(cnow==cto)continue;
        dup[cto]++;dum[cnow]++;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值