比较简单吧。。套模板。。
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;
}