문제: https://www.acmicpc.net/problem/2150
실제 책에 소개되는 알고리즘
참고 : https://jason9319.tistory.com/98
Graph STRONGLY_CONNECTED_COMPONENTS(const Graph &G)
{
const int v = G.size()-1;
Graph SSC;
std::stack<int> DFSf; // DFS pop 순서대로 들어가있다.
std::vector<bool> visit(v+2 ,false);
for (int i = 1; i <= v; i++) {
if (visit[i] != true)
DFS(G, i, DFSf,visit); //DFS순회 순서를 S에 저장한다.
}
Graph TG(v + 1, (std::vector<int>()));//G^T
for (int i = 1; i <= v; i++)
{
for (int j : G[i])
{
TG[j].push_back(i);
}
}
visit.assign(v+1,false);
for (int i = 0; i < v; i++)
{
if (visit[DFSf.top()] != true)
{
SSC.push_back(std::vector<int>());
TDFS(TG, DFSf.top(), SSC[SSC.size()-1],visit);
///SSC_n++;
}
DFSf.pop();
}
return SSC;
}with for
void DFS(const Graph &G, int x, std::stack<int>& DFSf , std::vector<bool> &visit)
{
visit[x] = true;
std::stack<int> sub_s;
sub_s.push(x);
while (!sub_s.empty())
{
int y = sub_s.top();
for (std::size_t i = 0; i < G[y].size(); i++)
{
int next = G[y][i];
if (visit[next] != true)
{
visit[next] = true;
sub_s.push(next);
i = -1;
y = sub_s.top();
}
}
DFSf.push(sub_s.top());//기존 DFS와 차이 STACK에 종료 순서 저장
sub_s.pop();
}
}with recursion
void DFS(const Graph& G, int x, std::stack<int>& DFSf, std::vector<bool>& visit)
{
visit[x] = true;
//std::cout << x << ' '; // 순회출력
for (int next : G[x])
{
if (visit[next] != true)
{
DFS(G, next, DFSf,visit);
}
}
DFSf.push(x);//기존 DFS와 차이 STACK에 종료 순서 저장
}with for
void TDFS(Graph &TG, int x,std::vector<int> &SSC, std::vector<bool> &visit)//G^T탐색
{
visit[x] = true;
std::stack<int> sub_s;
sub_s.push(x);
//std::cout << sub_s.top() << ' '; // 순회출력
while (!sub_s.empty())
{
int y = sub_s.top();
for (std::size_t i = 0; i < TG[y].size(); i++)
{
int next = TG[y][i];
if (visit[next] != true)
{
visit[next] = true;
sub_s.push(next);
//std::cout << sub_s.top() << ' '; // 순회출력
i = -1;
y = sub_s.top();
}
}
SSC.push_back(sub_s.top());
sub_s.pop();
}
}with recursion
//SSC[] 1D vector
void TDFS(Graph& TG, int x, std::vector<int>& SSC, std::vector<bool>& visit)
{
visit[x] = true;
//std::cout << x << ' '; // 순회출력
for (int next : TG[x])
{
if (visit[next] != true)
{
TDFS(TG, next, SSC,visit);
}
}
SSC.push_back(x);
}해당 코드를 토대로 매개변수를 옮김
// 자신의 결과값을 리턴하는 DFS 함수
int DFS(int curr, vector<vector<int>>& SCC,
vector<bool>& finished, stack<int>& S, vector<vector<int>>& adj, vector<int>& dfsn, int &cnt)
{
dfsn[curr] = ++cnt; // dfsn 결정
S.push(curr); // 스택에 자신을 push
// 자신의 dfsn, 자식들의 결과나 dfsn 중 가장 작은 번호를 result에 저장
int result = dfsn[curr];
for (int next : adj[curr])
{
// 아직 방문하지 않은 이웃
if (dfsn[next] == 0)
{
result = min(result, DFS(next, SCC, finished, S, adj, dfsn, cnt));
}
// 방문은 했으나 아직 SCC로 추출되지는 않은 이웃
else if (!finished[next])
{
result = min(result, dfsn[next]);
}
}
// 자신, 자신의 자손들이 도달 가능한 제일 높은 정점이 자신일 경우 SCC 추출
if (result == dfsn[curr])
{
vector<int> currSCC;
// 스택에서 자신이 나올 때까지 pop
while (1)
{
int t = S.top();
S.pop();
currSCC.push_back(t);
finished[t] = true;
//sn[t] = SN;
if (t == curr)
{
break;
}
}
// 출력을 위해 원소 정렬
sort(currSCC.begin(), currSCC.end());
// SCC 추출
SCC.push_back(currSCC);
}
return result;
}
std::vector<vector<int>> TARJAN_ALG(std::vector<vector<int>>& adj)
{
const int V = adj.size();
std::vector<int> dfsn(V + 1);
std::vector<vector<int>> SCC;
std::stack<int> S;
std::vector<bool> finished(V + 1); // SCC 분리가 끝난 정점만 true
int cnt = 0 ;
for (int i = 0; i < V - 1 ; i++)
{
if (dfsn[i] == 0)
{
DFS(i, SCC, finished, S, adj, dfsn,cnt);
}
}
return SCC;
}