这个题如果用传递闭包,显然是不行的。结点有10000个,效率O(N*N*N)
还好有个Korasaju算法:
procedure Strongly_Connected_Components(G);
begin
1.深度优先遍历G,算出每个结点u的结束时间f[u],起点如何选择无所谓。
2.深度优先遍历G的转置图GT,选择遍历的起点时,按照结点的结束时间从大到小进行。遍历的过程中,一边遍历,一边给结点做分类标记,每找到一个新的起点,分类标记值就加1。
3. 第2步中产生的标记值相同的结点构成深度优先森林中的一棵树,也即一个强连通分量
end;
这里将同一强连通分支的结点弄成一个点,然后找出度为0的点,如果出度为0的点只有一个,那么可解,解为出度为0的强连通分支上的所有点的个数。
对于DAG图有个定理:DAG图中唯一出度为0的点,一定可以由任何点出发均可达(由于无环,所以从任何点出发往前走,必然终止于一个出度为0的点);
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXM=50000;
const int MAXN=10000;
int finish[MAXN+5];
vector<int> adjacent[MAXN+5];
vector<int> radjacent[MAXN+5];
bool visit[MAXN+5];
int finishtime;
int distribute[MAXN+5];
bool same[MAXN+5];
void dfs(int u)
{
int size;
int i;
visit[u]=true;
size=adjacent[u].size();
for(i=0;i<size;i++)
{
if(visit[adjacent[u][i]]==false)
{
visit[adjacent[u] [i]]=true;
dfs(adjacent[u][i]);
}
}
finishtime++;
finish[finishtime]=u;
}
void rdfs(int u,int num)
{
int i;
int size=radjacent[u].size();
visit[u]=true;
distribute[u ]=num;
for(i=0;i<size;i++)
{
if(visit[radjacent[u][i]]==false)
{
visit[radjacent[u][i]]=true;
distribute[radjacent[u][i]]=num;
rdfs(radjacent[u][i],num);
}
}
}
int main()
{
int N,M;
int i;
int j;
int from,to;
while(scanf("%d %d",&N,&M)!=EOF)
{
for(i=1;i<=M;i++)
{
scanf("%d %d",&from,&to);
adjacent[from].push_back(to);
radjacent[to].push_back(from);//图的转置
}
finishtime=0;
memset(visit,false,sizeof(visit));
for(i=1;i<=N;i++)
{
if(visit[i]==false)
{
dfs(i);
}
}//对图DFS,按结束时间进栈,先结束先进栈
memset(visit,false,sizeof(visit));
int num=1;
for(i=finishtime;i>=1;i--)
{
if(visit[finish[i]]==false)
{
rdfs(finish[i],num);
num++;
}
}//对转置的图DFS,按出栈顺序DFS
num--;
memset(same,0,sizeof(same));
for(i=1;i<=N;i++)
{
for(j=0;j<adjacent[i].size();j++)
{
if(distribute[i]!=distribute[adjacent[i][j]])
{
same[distribute[i]]=1;//标记出度不为0的块
}
}
}
int sub;
int same_sum=0;
for(i=1;i<=num;i++)
{
if(same[i]==0)
{
sub=i;
same_sum++;//统计出度为0的块的个数
}
}
int ans;
ans=0;
if(same_sum>1)
{
printf("0/n");
continue;
}//出度为0的块的数量超过1
else
{
for(i=1;i<=N;i++)
{
if(distribute[i]==sub)
{
ans++;
}
}//统计出度为0的块的节点的个数
printf("%d/n",ans);
}
}
return 0;
}
参考文献:北大2010summerschool的gw_connect.ppt