티스토리 뷰

알고리즘/그래프

최소 공통 조상(LCA)

산타 브라운 2018. 9. 1. 20:22

11438 LCA 2 : https://www.acmicpc.net/problem/11438


LCA

- 서로의 깊이를 맞추거나 서로가 같아지는 정점을 찾을 때, 크게 움직이기 위해서 각 정점의 부모 뿐 아니라 2^k번 째 부모까지 저장하여 하나씩 올라가는 작업을 2^k씩 올라간다.

- DP 정의 : parent[K][V] = V번 정점의 2^k번 째 부모 정점 번호

parent[K][V] = parent[K-1]parent[K-1][V]]


1) par[0][] 셋팅

2) par[][] 모두 값 셋팅

3) a, b높이를 같게 맞춤

4) a, b의 최소 공통 조상을 찾아 binary search

5) a==b 이면 노드 자체가 조상. 그 외 a != b 이면 바로 위 조상(par[0][a])


#include <cstdio>

#include <vector>

#include <queue>

using namespace std;

#define KMAX 17 // 2^17 = 131072

int N, M;

vector <int> adj[100001];

queue <int> que;

int depth[100001]; //visit 정보

int par[KMAX + 1][100001];


int main()

{

    scanf("%d", &N);

    for (int i = 0; i <= N; i++)

    { //초기화

        depth[i] = -1;

        adj[i].clear();

        for (int k = 0; k<KMAX + 1; k++) par[k][i] = 0;

    }

    for (int i = 1; i<N; i++)

    {

        int from, to;

        scanf("%d %d", &from, &to);

        adj[from].push_back(to);

        adj[to].push_back(from);

    }

    

    // 트리 만들기

    depth[1] = 0;

    par[0][1] = 1;

    que.push(1);

    while (!que.empty())

    {

        int node = que.front(); que.pop();

        int len = adj[node].size();

        for (int i = 0; i<len; i++) // par[0][] 업데이트

        {

            int nnode = adj[node][i];

            if (depth[nnode] == -1) //노드 방문안했으면,

            {

                par[0][nnode] = node; //nnode의 부모는 node

                depth[nnode] = depth[node] + 1; // depth 갱신

                que.push(nnode);

            }

        }

    }

    

    // make sparse table : 나머지 par[][] 업데이트

    for (int k = 1; k<KMAX + 1; k++)

    {

        for (int n = 1; n <= N; n++)

        {

            // n의 2^k번째 조상은 n의 2^(k-1)번째 조상의 2^(k-1)번째 조상.

            // 2^k = 2^(k-1) + 2^(k-1)

            par[k][n] = par[k - 1][par[k - 1][n]]; // 점화식*****

        }

    }

    

    scanf("%d", &M);

    for (int i = 0, a, b; i<M; i++)

    {

        scanf("%d %d", &a, &b);

        

        //a의 높이를 b와 맞춘다.

        if (depth[a] < depth[b])

        {

            for (int k = KMAX; k >= 0; k--)

            {

                if (a != b && depth[par[k][b]] >= depth[a]) b = par[k][b];

            }

        }

        else if (depth[a] > depth[b])

        {

            for (int k = KMAX; k >= 0; k--)

            {

                if (a != b && depth[par[k][a]] >= depth[b]) a = par[k][a];

            }

        }

        

        int ans;

        

        //유사 binary search

        for (int k = KMAX; k >= 0; k--)

        {

            if (a != b && par[k][a] != par[k][b])

            {

                a = par[k][a];

                b = par[k][b];

            }

        }

        

        // 두 노드가 같다면 -> a는 b의 조상. -> LCA = a

        if (a == b) ans = a;

        else ans = par[0][a]; // 그외, a의 조상 또는 b의 조상

        printf("%d\n", ans);

    }

}



'알고리즘 > 그래프' 카테고리의 다른 글

벨만-포드 알고리즘  (0) 2018.09.02
다익스트라 알고리즘  (0) 2018.09.02
크루스칼 알고리즘 - 최소 신장 트리 (MST)  (0) 2018.09.01
위상정렬  (0) 2018.09.01
서로소 집합(Disjoint Set, Union-Find)  (0) 2018.09.01
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함