POJ 2186 强连通分量

比较简单吧。。套模板。。

Gabow

#include "cstdlib" 
#include "cctype" 
#include "cstring" 
#include "cstdio" 
#include "cmath" 
#include "algorithm" 
#include "vector" 
#include "string" 
#include "iostream" 
#include "sstream" 
#include "set" 
#include "queue" 
#include "stack" 
#include "fstream" 
#include "strstream" 
using namespace std;
#define  M 20000              //题目中可能的最大点数       
int STACK[M],top=0;          //Gabow 算法中的辅助栈 
int STACK2[M],top2=0;        // 
int DFN[M];                  //深度优先搜索访问次序 
int ComponetNumber=0;        //有向图强连通分量个数 
int Index=0;                 //索引号 
int Belong[M];               //某个点属于哪个连通分支 
vector Edge[M];        //邻接表表示 
vector Component[M];   //获得强连通分量结果 
bool bcount[M]={0};
void Gabow(int i) 
{ 
    int j; 
    DFN[i]=Index++; 
    STACK[++top]=i; 
    STACK2[++top2]=i; 
    for (int e=0;e<Edge[i].size();e++) 
    { 
        j=Edge[i][e]; 
        if (DFN[j]==-1)  Gabow(j); 
        else if (Belong[j]==-1)       //如果访问过,但没有删除,维护STACK2 
        { 
            while(DFN[STACK2[top2]]>DFN[j])        //删除构成环的顶点 
                top2--; 
        } 
    } 
    if(i==STACK2[top2])               //如果Stack2 的顶元素等于i,输出相应的强连通分量 
    { 
        --top2; ++ComponetNumber; 
        do 
        { 
            Belong[STACK[top]]=ComponetNumber; 
            Component[ComponetNumber].push_back(STACK[top]); 
        }while ( STACK[top--]!=i); 
    } 
}
void solve(int N)     //此图中点的个数,注意是0-indexed! 
{ 
    memset(STACK,-1,sizeof(STACK)); 
    memset(STACK2,-1,sizeof(STACK2)); 
    memset(Belong,-1,sizeof(Belong)); 
    memset(DFN,-1,sizeof(DFN));
    for(int i=0;i<N;i++) 
        if(DFN[i]==-1) 
            Gabow(i);    
} 
void reshape(int N)     //缩点形成新图,N为图中的点数 
{ 
    //bool ComDIG[M][M]; 
    //memset(ComDIG,0,sizeof(ComDIG)); 
    for( int i =0 ; i<  N;i++)       //一个顶点是i 
    { 
        for(int j=0;j<Edge[i].size();j++) //另外一个顶点是edge[i][j] 
        { 
            if(Belong[i]!=Belong[Edge[i][j]]) 
                bcount[Belong[i]]=true; 
            //    ComDIG[Belong[i]][Belong[Edge[i][j]]]=true; 
        } 
    } 
    /*for( int i =1 ;i<=ComponetNumber;i++) 
    { 
        for(int j=1;j<=ComponetNumber;j++) 
        { 
            if(ComDIG[i][j]) 
                cout<<i<<"     "<<j<<endl; 
        } 
    }*/
} 
/* 
此算法正常工作的基础是图是0-indexed的。但是获得的结果Component数组和Belong数组是1-indexed 
*/ 
int main() 
{
    int n,m;     //n个点,m条边
    while(scanf("%d %d",&n,&m)==2) 
    { 
        int a,b; 
        int ncount[M]={0}; //定义收缩之后连通分量的出度 
        for(int i=0;i<m;i++) 
        { 
            scanf("%d %d",&a,&b); 
            a--,b--; 
            Edge[a].push_back(b); 
        } 
        int  N=n; 
        solve(N); 
        reshape(N); 
        int time=0,ans=0; 
        for(int i=1;i<=ComponetNumber;i++) 
            if(!bcount[i]) 
            { 
                ans=Component[i].size(); 
                time++; 
            } 
        if(time==1) 
            printf("%d/n",ans); 
        else 
        printf("%d/n",0); 
    } 
    return 0; 
}


 

Kosaraju

 

#include "cstdlib" 
#include "cctype" 
#include "cstring" 
#include "cstdio" 
#include "cmath" 
#include "algorithm" 
#include "vector" 
#include "string" 
#include "iostream" 
#include "sstream" 
#include "set" 
#include "queue" 
#include "stack" 
#include "fstream" 
#include "strstream" 
using namespace std; 
#define M 20000 
bool vis[M];                 //遍历数组 
int post[M];                 //时间戳对应的点 
int timestamp;               //时间戳 
int ComponetNumber=0;        //有向图强连通分量个数 
int Belong[M]; 
vector Edge[M];        //邻接表表示 
vector Opp[M];         //原图的反图 
vector Component[M];   //获得强连通分量结果 
bool bcount[M]={0};
void dfs(int u) {             //第一个dfs确定时间戳 
    vis[u] = true; 
    for(int i=0;i<Edge[u].size();i++) { 
        if(vis[ Edge[u][i]])    continue; 
        //cout<<Edge[u][i]<<endl; 
        dfs(Edge[u][i]); 
    } 
    //cout<<"timestamp    "<<timestamp<<"       "<<u<<endl;    
    post[timestamp++] = u; 
}
void dfs2(int u) {      //第二个反边dfs确定连通块 
    vis[u] = true; 
    Component[ComponetNumber].push_back(u); 
    Belong[u]=ComponetNumber; 
    for(int i=0;i<Opp[u].size();i++) 
    { 
        int v = Opp[u][i]; 
        if(vis[v])  continue; 
        dfs2(v); 
    } 
}
void Kosaraju(int n) { 
    memset(Belong,0,sizeof(Belong)); 
    memset(vis,0,sizeof(vis)); 
    timestamp = 0; 
    for(int i=0;i<n;i++) { 
        if(vis[i])    continue; 
        dfs(i); 
    } 
    memset(vis,0,sizeof(vis)); 
    ComponetNumber++; 
    for(int i=n-1;i>=0;i--) {//按时间戳从大到小搜 
        if(vis[post[i]])    continue; 
        Component[ComponetNumber].clear(); 
        dfs2(post[i]); 
        ComponetNumber++; 
    } 
    ComponetNumber--;      //最后我们把块加了1。。所以要减掉 
} 
void reshape(int N)     //缩点形成新图,N为图中的点数 
{ 
    //bool ComDIG[M][M]; 
    //memset(ComDIG,0,sizeof(ComDIG)); 
    for( int i =0 ; i<  N;i++)       //一个顶点是i 
    { 
        for(int j=0;j<Edge[i].size();j++) //另外一个顶点是edge[i][j] 
        { 
            if(Belong[i]!=Belong[Edge[i][j]]) 
                bcount[Belong[i]]=true; 
            //    ComDIG[Belong[i]][Belong[Edge[i][j]]]=true; 
        } 
    } 
    /*for( int i =1 ;i<=ComponetNumber;i++) 
    { 
        for(int j=1;j<=ComponetNumber;j++) 
        { 
            if(ComDIG[i][j]) 
                cout<<i<<"     "<<j<<endl; 
        } 
    }*/
}
// 此算法工作的前提仍然是0-indexed 
int main() 
{
    int n,m;     //n个点,m条边
    while(scanf("%d %d",&n,&m)==2) 
    { 
        int a,b; 
        int ncount[M]={0}; //定义收缩之后连通分量的出度 
        for(int i=0;i<m;i++) 
        { 
            scanf("%d %d",&a,&b); 
            a--,b--; 
            Edge[a].push_back(b); 
            Opp[b].push_back(a); 
        } 
        int  N=n; 
        Kosaraju(N); 
        reshape(N); 
        int time=0,ans=0; 
        for(int i=1;i<=ComponetNumber;i++) 
            if(!bcount[i]) 
            { 
                ans=Component[i].size(); 
                time++; 
            } 
            if(time==1) 
                printf("%d/n",ans); 
            else 
                printf("%d/n",0); 
    } 
    return 0; 
}
 

 

Tarjan

 

#include "cstdlib" 
#include "cctype" 
#include "cstring" 
#include "cstdio" 
#include "cmath" 
#include "algorithm" 
#include "vector" 
#include "string" 
#include "iostream" 
#include "sstream" 
#include "set" 
#include "queue" 
#include "stack" 
#include "fstream" 
#include "strstream" 
using namespace std;
#define  M 10005             //题目中可能的最大点数       
int STACK[M],top=0;          //Tarjan 算法中的栈 
bool InStack[M];             //检查是否在栈中 
int DFN[M];                  //深度优先搜索访问次序 
int Low[M];                  //能追溯到的最早的次序 
int ComponetNumber=0;        //有向图强连通分量个数 
int Belong[M]; 
int Index=0;                 //索引号 
vector Edge[M];        //邻接表表示 
vector Component[M];   //获得强连通分量结果 
//bool ComDIG[M][M]; 
bool bcount[M]={0};
void Tarjan(int i) 
{ 
    int j; 
    DFN[i]=Low[i]=Index++; 
    InStack[i]=true; 
    STACK[++top]=i; 
    for (int e=0;e<Edge[i].size();e++) 
    { 
        j=Edge[i][e]; 
        if (DFN[j]==-1) 
        { 
            Tarjan(j); 
            Low[i]=min(Low[i],Low[j]); 
        } 
        else if (InStack[j]) 
            Low[i]=min(Low[i],DFN[j]); 
    } 
    if (DFN[i]==Low[i]) 
    { 
        //cout<<"TT    "<<i<<"   "<<Low[i]<<endl; 
        ComponetNumber++; 
        do 
        { 
            j=STACK[top--]; 
            InStack[j]=false; 
            Component[ComponetNumber].push_back(j); 
            Belong[j]=ComponetNumber; 
        } 
        while (j!=i); 
    } 
}
void solve(int N)     //此图中点的个数,注意是0-indexed! 
{ 
    memset(STACK,-1,sizeof(STACK)); 
    memset(InStack,0,sizeof(InStack)); 
    memset(DFN,-1,sizeof(DFN)); 
    memset(Low,-1,sizeof(Low)); 
    memset(Belong,0,sizeof(Belong)); 
    for(int i=0;i<N;i++) 
        if(DFN[i]==-1) 
            Tarjan(i);    
} 
void reshape(int N)     //缩点形成新图,N为图中的点数 
{ 
    //bool ComDIG[M][M]; 
    //memset(ComDIG,0,sizeof(ComDIG)); 
    for( int i =0 ; i<  N;i++)       //一个顶点是i 
    { 
        for(int j=0;j<Edge[i].size();j++) //另外一个顶点是edge[i][j] 
        { 
            if(Belong[i]!=Belong[Edge[i][j]]) 
                bcount[Belong[i]]=true; 
            //    ComDIG[Belong[i]][Belong[Edge[i][j]]]=true; 
        } 
    } 
    /*for( int i =1 ;i<=ComponetNumber;i++) 
    { 
        for(int j=1;j<=ComponetNumber;j++) 
        { 
            if(ComDIG[i][j]) 
                cout<<i<<"     "<<j<<endl; 
        } 
    }*/
} 
/* 
此算法正常工作的基础是图是0-indexed的。 
*/ 
int main() 
{
    int n,m;     //n个点,m条边
    while(scanf("%d %d",&n,&m)==2) 
    { 
        int a,b; 
        int ncount[M]={0}; //定义收缩之后连通分量的出度 
        for(int i=0;i<m;i++) 
        { 
            scanf("%d %d",&a,&b); 
            a--,b--; 
            Edge[a].push_back(b); 
        } 
        int  N=n; 
        solve(N); 
        reshape(N); 
    /*    for(int i=1;i<=ComponetNumber;i++) 
        { 
            for(int j=0;j<ComponetNumber;j++) 
            { 
                if(ComDIG[i][j]) 
                    bcount[i]++; 
            } 
        }*/ 
        int time=0,ans=0; 
        for(int i=1;i<=ComponetNumber;i++) 
            if(!bcount[i]) 
            { 
                ans=Component[i].size(); 
                time++; 
            } 
        if(time==1) 
            printf("%d/n",ans); 
        else 
        printf("%d/n",0); 
    } 
    return 0; 
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值