强连通分量 (kosaraju算法+tarjan算法)

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了强连通分量 (kosaraju算法+tarjan算法)相关的知识,希望对你有一定的参考价值。

数组都开得我麻木了。。。。

P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G

https://www.luogu.com.cn/problem/P2341

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
int n,m,head[maxn],cnt,dfn[maxn],low[maxn],bl[maxn],tim;
int inq[maxn],v[maxn],nxt[maxn],tol,in[maxn],ans,du[maxn];
stack<int>q;
void add(int u,int v1)

    v[++cnt]=v1;
    nxt[cnt]=head[u];
    head[u]=cnt;

void tarjan(int u)

    dfn[u]=low[u]=++tim;
    q.push(u);
    inq[u]=1;
    for(int i=head[u];i;i=nxt[i])
    
        int v1=v[i];
        if(!dfn[v1])
        
            tarjan(v1);
            low[u]=min(low[u],low[v1]);
        
        else if(inq[v1])
            low[u]=min(low[u],dfn[v1]);
    
    if(dfn[u]==low[u])
    
        tol++;int tmp;
        do
            tmp=q.top();
            q.pop();
            inq[tmp]=0;
            in[tol]++;   //此强连通分量的点点数
            bl[tmp]=tol;  //缩点操作
        while(tmp!=u);
    

int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    
        int u,v1;scanf("%d%d",&u,&v1);
        add(u,v1);
    
    for(int i=1;i<=n;i++)
    
        if(!dfn[i])
            tarjan(i);
    
    for(int f=1;f<=n;f++)
    
        for(int i=head[f];i;i=nxt[i])
        
            int vv=v[i];
            if(bl[f]!=bl[vv])
            
                du[bl[f]]++;
            
        
    
    int tt=0;
    for(int i=1;i<=tol;i++)
    
        if(!du[i])
        
            if(tt)
            
                cout<<0<<endl;
                return 0;
            
            tt=i;  //只能一个点出度为0
        
    
    cout<<in[tt]<<endl;
    return 0;

P2863 [USACO06JAN]The Cow Prom S

https://www.luogu.com.cn/problem/P2863

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e6+5;
int n,m,g[2][maxn],v[2][maxn],nxt[2][maxn],tmp,cnt,cc,q[maxn],f[maxn],t,ans;
bool vis[maxn];
void add(int u,int vv)

    v[0][++cnt]=vv;
    nxt[0][cnt]=g[0][u];
    g[0][u]=cnt;

void add1(int u,int vv)

    v[1][++cc]=vv;
    nxt[1][cc]=g[1][u];
    g[1][u]=cc;

void dfs1(int x)

    vis[x]=1;
    for(int i=g[0][x];i;i=nxt[0][i])
    
        if(!vis[v[0][i]])
        
            dfs1(v[0][i]);
        
    
    q[++t]=x;

void dfs2(int x,int y)

    vis[x]=0;f[x]=y;
    tmp++;
    for(int i=g[1][x];i;i=nxt[1][i])
    
        if(vis[v[1][i]])
            dfs2(v[1][i],y);
    

int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    
        int u,vv;scanf("%d%d",&u,&vv);
        add(u,vv);
        add1(vv,u);
    
    for(int i=1;i<=n;i++)
    
        if(!vis[i])
            dfs1(i);
    
    for(int i=n;i>=1;i--)
    
        tmp=0;
        if(vis[q[i]])
            dfs2(q[i],q[i]);
        if(tmp>1)
            ans++;
    
    cout<<ans<<endl;
    return 0;

https://www.luogu.com.cn/problem/P2835

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
int n,head[maxn],cnt,dfn[maxn],low[maxn],bl[maxn],tim;
int inq[maxn],v[maxn],nxt[maxn],tol,in[maxn],ans;
stack<int>q;
void add(int u,int v1)

    v[++cnt]=v1;
    nxt[cnt]=head[u];
    head[u]=cnt;

void tarjan(int u)

    dfn[u]=low[u]=++tim;
    q.push(u);
    inq[u]=1;
    for(int i=head[u];i;i=nxt[i])
    
        int v1=v[i];
        if(!dfn[v1])
        
            tarjan(v1);
            low[u]=min(low[u],low[v1]);
        
        else if(inq[v1])
            low[u]=min(low[u],dfn[v1]);
    
    if(dfn[u]==low[u])
    
        tol++;int tmp;
        do
            tmp=q.top();
            q.pop();
            inq[tmp]=0;
            bl[tmp]=tol;
        while(tmp!=u);
    

int main()

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    
        int v1;
        while(scanf("%d",&v1)&&v1)
            add(i,v1);
    
    for(int i=1;i<=n;i++)
    
        if(!dfn[i])
            tarjan(i);
    
    for(int u=1;u<=n;u++)
    
        for(int i=head[u];i;i=nxt[i])
        
            if(bl[u]!=bl[v[i]])
            
                in[bl[v[i]]]++;
            
        
    
    for(int i=1;i<=tol;i++)
        if(!in[i])
        ans++;
    cout<<ans<<endl;
    return 0;

P2002 消息扩散

https://www.luogu.com.cn/problem/P2002

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e6+5;
int n,m,head[maxn],cnt,dfn[maxn],low[maxn],tim;
int inq[maxn],v[maxn],nxt[maxn],tol,ans,du[maxn],bl[maxn],in[maxn];
stack<int>q;
void add(int u,int v1)

    v[++cnt]=v1;
    nxt[cnt]=head[u];
    head[u]=cnt;

void tarjan(int u)

    dfn[u]=low[u]=++tim;
    q.push(u);
    inq[u]=1;
    for(int i=head[u];i;i=nxt[i])
    
        int v1=v[i];
        if(!dfn[v1])
        
            tarjan(v1);
            low[u]=min(low[u],low[v1]);
        
        else if(inq[v1])
            low[u]=min(low[u],dfn[v1]);
    
    if(dfn[u]==low[u])
    
        tol++;int tmp;
        do
            tmp=q.top();
            q.pop();
            inq[tmp]=0;
            in[tmp]=tol;
        while(tmp!=u);
    

int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    
        int u,v1;scanf("%d%d",&u,&v1);
        add(u,v1);
    
    for(int i=1;i<=n;i++)
    
        if(!dfn[i])
            tarjan(i);
    
    for(int f=1;f<=n;f++)
    
        for(int i=head[f];i;i=nxt[i])
        
            int vv=v[i];
            if(in[f]!=in[vv])
            
                du[in[vv]]++;
            
        
    
    for(int i=1;i<=tol;i++)
    
        if(!du[i]) ans++;
    
    cout<<ans<<endl;
    return 0;

以上是关于强连通分量 (kosaraju算法+tarjan算法)的主要内容,如果未能解决你的问题,请参考以下文章

连通图算法详解之① :Tarjan 和 Kosaraju 算法

请问如何求(有向/无向)图的强连通分量,还有,基础一点,怎么求有几个连通图啊

浅析强连通分量(Tarjan和kosaraju)

Kosaraju 算法

POJ2186 Popular Cows 强连通分量+Kosaraju+Tarjan+Garbow

bzoj1051[kosaraju算法]求强连通分量