알고리즘
SCC - kosaraju
clichy12
2019. 5. 21. 00:27
SCC ( Strongly Connected Component )
강한 연결 요소, 집합 내에서 서로 왕복 가능한 최대 집합의 크기
https://www.acmicpc.net/problem/2150
2150번: Strongly Connected Component
첫째 줄에 두 정수 V(1≤V≤10,000), E(1≤E≤100,000)가 주어진다. 이는 그래프가 V개의 정점과 E개의 간선으로 이루어져 있다는 의미이다. 다음 E개의 줄에는 간선에 대한 정보를 나타내는 두 정수 A, B가 주어진다. 이는 A번 정점과 B번 정점이 연결되어 있다는 의미이다. 이때 방향은 A->B가 된다.
www.acmicpc.net
- 방향 그래프, 역방향 그래프, 스택을 준비한다.
- 방향 그래프를 사용하여 dfs를 수행하고, 끝나는 순서대로 스택에 push한다. (단, 모든 정점에 대해서 수행)
- 스택을 비울 때까지 pop을 하면서, 역방향 그래프를 사용하여 dfs를 수행하고 모든 정점들을 같은 SCC로 묶는다.
[ JAVA ]
class Main {
static ArrayList<Integer> graph[];
static ArrayList<Integer> reverse[];
static boolean visited[];
static Stack<Integer> st = new Stack<>();
// Result
static ArrayList<ArrayList<Integer>> a = new ArrayList<>();
static void dfs(int now) {
for (int a : graph[now]) {
if (visited[a] == false) {
visited[a] = true;
dfs(a);
}
}
st.push(now);
}
static void rdfs(int base, ArrayList<Integer> temp) {
temp.add(base);
for (int a : reverse[base]) {
if (!visited[a]) {
visited[a] = true;
rdfs(a, temp);
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
int n = Integer.parseInt(stk.nextToken());
int m = Integer.parseInt(stk.nextToken());
graph = new ArrayList[n + 1];
reverse = new ArrayList[n + 1];
visited = new boolean[n + 1];
for (int i = 1; i <= n; i++) {
graph[i] = new ArrayList<>();
reverse[i] = new ArrayList<>();
}
for (int i = 0; i < m; i++) {
stk = new StringTokenizer(br.readLine());
int from = Integer.parseInt(stk.nextToken());
int to = Integer.parseInt(stk.nextToken());
graph[from].add(to);
reverse[to].add(from);
}
// stack
for (int i = 1; i <= n; i++) {
if (!visited[i]) {
visited[i] = true;
dfs(i);
}
}
Arrays.fill(visited, false);
while (!st.isEmpty()) {
int base = st.pop();
if (!visited[base]) {
visited[base] = true;
ArrayList<Integer> temp = new ArrayList<>();
rdfs(base, temp);
Collections.sort(temp);
temp.add(-1);
a.add(temp);
}
}
Collections.sort(a, new Comparator<ArrayList<Integer>>() {
@Override
public int compare(ArrayList<Integer> o1, ArrayList<Integer> o2) {
return Integer.compare(o1.get(0), o2.get(0));
}
});
StringBuilder sb = new StringBuilder();
sb.append(a.size()).append("\n");
for (int i = 0; i < a.size(); i++) {
int size = a.get(i).size();
for (int j = 0; j < size; j++) {
sb.append(a.get(i).get(j)).append(" ");
}
sb.append("\n");
}
System.out.println(sb);
br.close();
}
}
[ C++ ]
#include <stdio.h>
#include <memory.h>
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<int> vi;
const int v_ = 1e4 + 1;
int v, e, cnt, pos, stk[v_];
bool vst[v_];
vi gp1[v_], gp2[v_];
vector<vi> res;
void dfs(int now)
{
vst[now] = true;
for (int nxt : gp1[now])
if (!vst[nxt])
dfs(nxt);
stk[pos++] = now;
}
void scc(int now)
{
vst[now] = true;
res[cnt].push_back(now);
for (int nxt : gp2[now])
if (!vst[nxt])
scc(nxt);
}
int main()
{
int i;
scanf("%d %d", &v, &e);
for (i = 1; i <= e; i++)
{
int a, b;
scanf("%d %d", &a, &b);
gp1[a].push_back(b);
gp2[b].push_back(a);
}
for (i = 1; i <= v; i++)
if (!vst[i])
dfs(i);
memset(vst, 0, sizeof(vst));
while (pos)
{
int top = stk[--pos];
if (vst[top])
continue;
res.push_back(vi());
scc(top);
cnt++;
}
for (i = 0; i < cnt; i++)
sort(res[i].begin(), res[i].end());
sort(res.begin(), res.end(), [](const vi &i, const vi &j) { return i[0] < j[0]; });
printf("%d\n", res.size());
for (auto &i : res)
{
for (auto j : i)
printf("%d ", j);
puts("-1");
}
return 0;
}
https://jason9319.tistory.com/98
SCC(Strongly Connected Component)
방향 그래프에서 어떤 그룹 X에 있는 임의의 두 정점 A,B에 대해서 항상 A->B로 가는 경로가 존재한다면 그 그룹을 SCC(Strongly Connected Component)라 칭합니다. 더 정확하게 정의하자면 SCC가 되는 그룹은 항..
jason9319.tistory.com