https://www.acmicpc.net/problem/2150

 

2150번: Strongly Connected Component

첫째 줄에 두 정수 V(1 ≤ V ≤ 10,000), E(1 ≤ E ≤ 100,000)가 주어진다. 이는 그래프가 V개의 정점과 E개의 간선으로 이루어져 있다는 의미이다. 다음 E개의 줄에는 간선에 대한 정보를 나타내는 두 정

www.acmicpc.net

핵심::
코사라주 알고리즘 / 타잔 알고리즘 중 코사라주 알고리즘 풀이

SCC란::
강한 연결 방향 그래프

연결 그래프에 존재하는 부분 집합 Z에 속하는 모든 무작위 정점 (A, B)에 대해 A -> B로의 연결이 가능하다면 Z를 SCC라고 한다.

또한 SCC를 구분할 때에는 가장 큰 SCC만 찾도록 한다. 따라서 하나의 그래프에서 SCC를 구했을 때 정점이 겹칠 수 없다.

SCC를 구하는 대표적인 알고리즘은 코사라주 알고리즘과 타잔 알고리즘이 있으며 두 방식 모두 코드에 첨부하였다.

알고리즘은 설명은 별도의 글에서 하겠다.

의견::
솔직히 배울 때 쓸모없을 줄 알았는데 이걸에서 파생하는 문제 많음

타잔 코드::

더보기
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

vector<bool> vis, iscc;
vector<int> poslist;
vector<vector<int>> arr;
stack<int> st;
vector<vector<int>> scclist;
int cnt = 1;

bool cmp(vector<int> a, vector<int> b) {
	return a[0] < b[0];
}

int dfs(int x) {
	vis[x] = true;
	poslist[x] = cnt++;
	st.push(x);
	int mp = poslist[x];
	for (auto v : arr[x]) {
		if (!vis[v]) {
			int ret = dfs(v);
			mp = ret < mp ? ret : mp;
		}
		else if (!iscc[v]) {
			mp = mp < poslist[v] ? mp : poslist[v];
		}
	}

	if (poslist[x] == mp) {
		scclist.push_back({});
		while (!st.empty() && st.top() != x) {
			scclist[scclist.size() - 1].push_back(st.top());
			iscc[st.top()] = true;
			st.pop();
		}
		scclist[scclist.size() - 1].push_back(st.top());
		iscc[st.top()] = true;
		st.pop();
		sort(scclist[scclist.size() - 1].begin(), scclist[scclist.size() - 1].end());
	}

	return poslist[x] = mp;
}

int main()
{
	int n, m; cin >> n >> m;	
	vis = vector<bool>(n + 1, false);
	iscc = vector<bool>(n + 1, false);
	poslist = vector<int>(n + 1);
	arr = vector<vector<int>>(n + 1);

	for (int i = 1; i <= m; i++) {
		int s, e; cin >> s >> e;
		arr[s].push_back(e);
	}

	for (int i = 1; i <= n; i++) {
		if (vis[i]) continue;		
		//st = stack<int>();
		dfs(i);
	}

	sort(scclist.begin(), scclist.end(), cmp);
	
	cout << scclist.size() << "\n";
	for (int i = 0; i < scclist.size(); i++) {
		for (int j = 0; j < scclist[i].size(); j++) {
			cout << scclist[i][j] << " ";
		}
		cout << "-1\n";
	}

	return 0;
}

 

코사라주 코드::

더보기
#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;

bool cmp(vector<int> a, vector<int> b) {
	return a[0] < b[0];
}

int n, m;
vector<vector<int>> arr;
vector<vector<int>> rarr;
vector<bool> vis;
stack<int> fst;

void dfs(int x) {
	vis[x] = true;
	for (auto v : arr[x]) {
		if (vis[v]) continue;		
		dfs(v);
	}
	fst.push(x);
}

vector<int> find_scc(int x, vector<int> scc) {
	vis[x] = true;
	scc.push_back(x);
	for (auto v : rarr[x]) {
		if (vis[v]) continue;
		scc = find_scc(v, scc);
	}
	return scc;
}



int main()
{
	cin >> n >> m;
	arr.resize(n + 1); rarr.resize(n + 1);

	for (int i = 1; i <= m; i++) {
		int s, d;
		cin >> s >> d;
		arr[s].push_back(d);
		rarr[d].push_back(s);
	}

	vis = vector<bool>(n + 1, false);

	for (int i = 1; i <= n; i++) {
		if (vis[i]) continue;
		dfs(i);
	}		

	vis = vector<bool>(n + 1, false);
	
	vector<vector<int>> scc;

	while (!fst.empty()) {
		auto cur = fst.top(); fst.pop();
		if (vis[cur]) continue;
		auto ret = find_scc(cur, vector<int>());

		sort(ret.begin(), ret.end());
		scc.push_back(ret);
	}	

	sort(scc.begin(), scc.end(), cmp);

	cout << scc.size() << "\n";
	for (int i = 0; i < scc.size(); i++) {
		for (int j = 0; j < scc[i].size(); j++) {
			cout << scc[i][j] << " ";
		}
		cout << "-1\n";
	}

	return 0;
}