模板题目:http://poj.org/problem?id=2553
Kosaraju:按顺序对原图和反图DFS一遍,在第二次DFS时点u可达未DFS的点v则u,v属于同一个联通分量
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn = 5005;
int out[maxn];
int in[maxn];
vector<int> G[maxn];
vector<int> Gr[maxn];
vector<int> rG[maxn];
vector<int> P[maxn];
vector<int> ps;
int ID[maxn];
int n, m;
bool vis[maxn];
void DFS(int u)
{
vis[u] = true;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!vis[v]) DFS(v);
}
ps.push_back(u);
}
void RDFS(int u, int x)
{
vis[u] = true;
ID[u] = x;
P[x].push_back(u);
for(int i = 0; i < Gr[u].size(); i++)
{
int v = Gr[u][i];
if(!vis[v]) RDFS(v, x);
}
}
void init()
{
memset(out, 0, sizeof(out));
ps.clear();
for(int i = 1; i <= n; i++)
{
G[i].clear();
Gr[i].clear();
rG[i].clear();
P[i].clear();
}
}
int Kosaraju()
{
int res = 0;
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
if(!vis[i]) DFS(i);
}
memset(vis, 0, sizeof(vis));
for(int i = ps.size() - 1; i + 1; i--)
{
int v = ps[i];
if(!vis[v]) RDFS(v, ++res);
}
return res;
}
void Get_DAG()
{
for(int u = 1; u <= n; u++)
{
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(ID[u] != ID[v])
{
rG[ID[u]].push_back(ID[v]);
out[ID[u]]++;
}
}
}
}
int main()
{
while(cin >> n, n)
{
cin >> m;
init();
for(int i = 0; i < m; i++)
{
int u, v;
scanf("%d %d", &u, &v);
G[u].push_back(v);
Gr[v].push_back(u);
}
Kosaraju();
Get_DAG();
vector<int> ans;
for(int i = 1; i <= n; i++)
{
if(!out[i] && P[i].size())
{
for(int j = 0; j < P[i].size(); j++)
{
int v = P[i][j];
ans.push_back(v);
}
}
}
sort(ans.begin(), ans.end());
for(int i = 0; i < ans.size(); i++)
{
int v = ans[i];
cout << v << (v == ans.back() ? '\n' : ' ');
}
}
return 0;
}
Tarjan:对于一个强连通分量,其中的第一个点被dfs搜到的时候,接着一定是整个联通分量被遍历完并且回到最开始的点,这时候就可以对该dfs子树进行整体编号
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn = 5005;
int out[maxn];
stack<int> S;
vector<int> G[maxn];
vector<int> rG[maxn];
vector<int> P[maxn];
bool isinstack[maxn];
int low[maxn], dfn[maxn];
int ID[maxn];
int n, m, ssc_num, index;
void Get_DAG()
{
for(int u = 1; u <= n; u++)
{
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(ID[u] != ID[v])
{
rG[ID[u]].push_back(ID[v]);
out[ID[u]]++;
}
}
}
}
void init()
{
memset(out, 0, sizeof(out));
memset(dfn, -1, sizeof(dfn));
memset(isinstack, 0, sizeof(isinstack));
index = 1;
for(int i = 1; i <= n; i++)
P[i].clear(), G[i].clear(), rG[i].clear();
}
void TarDFS(int u)
{
dfn[u] = index++;
low[u] = dfn[u];
isinstack[u] = 1;
S.push(u);
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(dfn[v] == -1)
{
TarDFS(v);
low[u] = min(low[u], low[v]);
}
else if(isinstack[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] ==low[u])
{
ssc_num++;
while(S.top() != u)
{
isinstack[S.top()] = 0;
ID[S.top()] = ssc_num;
P[ssc_num].push_back(S.top());
S.pop();
}
isinstack[u] = 0;
ID[u] = ssc_num;
P[ssc_num].push_back(u);
S.pop();
}
}
int Tarjan()
{
ssc_num = 0;
index = 1;
for(int i = 1; i <= n; i++)
{
if(dfn[i] == -1)
{
TarDFS(i);
}
}
return ssc_num;
}
int main()
{
while(cin >> n, n)
{
cin >> m;
init();
for(int i = 0; i < m; i++)
{
int u, v;
scanf("%d %d", &u, &v);
G[u].push_back(v);
}
Tarjan();
Get_DAG();
vector<int> ans;
for(int i = 1; i <= n; i++)
{
if(!out[i] && P[i].size())
{
for(int j = 0; j < P[i].size(); j++)
{
int v = P[i][j];
ans.push_back(v);
}
}
}
sort(ans.begin(), ans.end());
for(int i = 0; i < ans.size(); i++)
{
int v = ans[i];
cout << v << (v == ans.back() ? '\n' : ' ');
}
}
return 0;
}