Articulation Point (단절점)

단절점(https://www.acmicpc.net/problem/11266) 문제에 대한 코드, 템플릿을 만들어주세요!

코드

#include <stdio.h>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> g[10001];
int discovered[10001], cnt;
bool ans[10001];

int dfs(bool is_root, int node)
{
    int i, ret, child = 0, low;
    discovered[node] = ++cnt;
    ret = discovered[node];

    for ( i = 0; i < g[node].size(); i++ ) {
        int u = g[node][i];
        if ( discovered[u] == 0 ) {
            child++;
            low = dfs(false, u);
            if ( is_root == false && low >= discovered[node] )
                ans[node] = true;
            ret = min(ret, low);
        }else
            ret = min(ret, discovered[u]);
    }

    if ( is_root && child >= 2 ) ans[node] = true;
    return ret;
}

int main()
{
    int v, e, a, b, i, cnt = 0;

    scanf("%d%d", &v, &e);
    while(e--) {
        scanf("%d%d", &a, &b);
        g[a].push_back(b);
        g[b].push_back(a);
    }

    for ( i = 1; i <= v; i++ )
        if ( discovered[i] == 0 )
            dfs(true, i);

    for ( i = 1; i <= v; i++ )
        if ( ans[i] )
            cnt++;

    printf("%d\n", cnt);
    for ( i = 1; i <= v; i++ )
        if ( ans[i] )
            printf("%d ", i);

    return 0;
}

정리

  • 단절점을 제거하고 요소 개수가 늘었는지 확인하는 방법은 각 단절점에 대한 dfs 를 수행하므로 시간복잡도는 O(V(V+E)) 이다. 스패닝 트리를 이용하면 O(V+E) 에 해결할 수 있다.
  • 알고리즘의 아이디어
    • 단절점 경로 이외의 우회 경로가 존재할 경우, 단절점이 아니다.
    • 스패닝 트리이기 때문에 DFS 를 순회할 때, 방문순서를 기재하게 되면 일반적으로 자식이 부모보다 큰 값을 가져야 한다
    • 만약 우회경로가 있다면 자식이 부모보다 더 작게된다
    • 결론적으로 자식들의 DFS 의 min 이 현재 방문순서보다 작다면(미만) 단절점이 아니라고 할 수 있다
    • 루트의 경우 자식이 1개 이하라면 단절점이 아니므로, 루트에 대해서만 예외적으로 자식이 2개 이상일때 단절점이다.
  • 구현 내용
    • DFS 탐색을 시작해서 방문하는 순서로 정점에 번호를 매긴다. (스패닝트리를 만든다)
    • 루트 일 경우
      • 자식이 2개 이상이면 단절점
    • 루트가 아닐 경우
      • 자식의 방문순서의 최소값이, 현재 탐색중인 노드의 방문순서보다 같거나 클 경우 단절점이다.

관련 문제

참고 자료

results matching ""

    No results matching ""