[Python] 11438 - LCA2 (플래티넘 5)

2022. 7. 14. 18:39·Coding Test/Solution

1. 문제 설명

 

11438번: LCA 2

첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정

www.acmicpc.net

난 하다가 Pypy로 제출해버렸는데, 지금 생각해보면 몇 가지 수정을 해주면 Python으로 충분히 통과할 수 있을 것 같다.

 


2. 아이디어

 

전 단계 방법을 그대로 사용해서 다익스트라 알고리즘을 곁들였는데 Python으로는 시간초과가 나서

Pypy로 제출했다.

 

포스팅을 하다가 갑자기 Pypy로 제출해서 통과한 게 자존심이 상해서 관련 알고리즘을 뒤져보니

HLD(Heavy Light Demoposion) 알고리즘이라는 걸 발견했다.

 

 

Heavy-Light Decomposition

서론 알고리즘 문제를 풀다 보면 많은 경우에 문제를 그래프 문제로 모델화할 수 있음을 보게 됩니다. 여러 요소들간의 관계가 주어지는 경우에는 각 요소를 정점으로, 관계를 간선으로 두는 방

www.secmem.org

가장 무거운 간선을 따라 내려간 경로를 찾아 트리를 묶으면,
트리 위의 어떠한 경로도 길이가 O(logn)을 넘지 않는다.

트리를 무식하게 순회하면 O(N)라는 시간 복잡도가 발생하므로 LCA라는 알고리즘을 사용하는 건데

이 알고리즘은 공간 복잡도가 O(NlogN)이기 때문에 현재 문제가 발생한다.

 

대충 원리만 설명하면 비선형 구조 트리를 선형 구조 트리로 만들어 버리면 segment tree 기법을 사용할 수 있게 된다.

균형 잡히지 않은 트리에서 균형 잡힌 트리의 구역(chain)을 나누어 다루는 것이다.

 

자세한 설명은 나중에 알고리즘 탭에서 할 거고 간단히 코드에 대한 설명을 하면

처음 dfs는 그래프의 기본적인 정보를 파악하여 현재(current)노드의 깊이, 부모 정점, 부트리의 정점의 수(무게)를

재귀적으로 계산한다.

그 다음 dfs는 root 노드를 시작으로 체인을 형성한다.

각 정점에서 가장 큰 자식만 정점의 체인을 이어나가고 나머지는 새로운 체인의 시작이 된다. (분가 형성)

hld 알고리즘 수행을 통해 얻어낸 chain들을 가지고 다시 LCA를 수행하면 해결되는 문제였다.

 

 


3. 코드

import sys

sys.setrecursionlimit(10**6)
input = sys.stdin.readline

def dfs(cur, pre):
    parent[cur] = pre # 현재 노드의 부모 노드 정보 업데이트
    size[cur] = 1 # 부트리 정점의 수 계산 

    for child in tree[cur]:
        if child == pre: # 부모 노드 제외
            continue
        size[cur] += dfs(child, cur) # 재귀 빠져나오면서 
    return size[cur]

def hld(cur, prev, chain_idx, depth):
    chain_depth[cur] = depth # 체인 구분
    belong_chain[cur] = chain_idx # 
    rel_pos_in_chain[cur] = len(chains[chain_idx]) # 현재 만들고 있는 체인 길이
    chains[chain_idx].append(cur) # 체인에 포함된 노드 업데이트

    max_idx = 0
    for child in tree[cur]:
        if child == prev:
            continue
        if size[child] > size[max_idx]:
            max_idx = child
    if max_idx != 0:
        hld(max_idx, cur, chain_idx, depth) # 현재 체인 확장
    for child in tree[cur]:
        if child == prev or child == max_idx:
            continue
        hld(child, cur, child, depth+1) # 새로운 체인 생성

def lca(a, b):
    while belong_chain[a] != belong_chain[b]: # 깊이 맞추기
        if chain_depth[a] > chain_depth[b]:
            a = parent[belong_chain[a]]
        else:
            b = parent[belong_chain[b]]
        
    if rel_pos_in_chain[a] > rel_pos_in_chain[b]:
        return b
    else:
        return a

def solution():
    m = int(input())

    dfs(1, 0) # parent info update
    hld(1, 0, 1, 0)

    for _ in range(m):
        a, b = map(int, input().split())
        print(lca(a, b))

if __name__ == "__main__":
    n = int(input())
    parent = [0] * (n+1)    # 각 노드의 부모 노드 info
    d = [0] * (n+1)         # 각 노드까지 깊이
    size = [0] * (n+1)
    tree = [[] for _ in range(n+1)]

    belong_chain = [-1] * (n+1)
    rel_pos_in_chain = [-1] * (n+1)
    chain_depth = [-1] * (n+1)
    chains = [[] for _ in range(n+1)]

    for _ in range(n-1):
        u, v = map(int, input().split())
        tree[u].append(v)
        tree[v].append(u)

    solution()
저작자표시 비영리 (새창열림)
'Coding Test/Solution' 카테고리의 다른 글
  • [C++] 1916 - 최소비용 구하기 (골드5)
  • [C++] 2293 - 동전 1 (골드5)
  • [Python] 11437 - LCA (골드3)
  • [Python] 11375 / 11376 / 11377 / 11378 - 열혈강호 (플래티넘3, 4) : 미해결
나죽못고나강뿐
나죽못고나강뿐
싱클레어, 대부분의 사람들이 가는 길은 쉽고, 우리가 가는 길은 어려워요. 우리 함께 이 길을 가봅시다.
  • 나죽못고나강뿐
    코드를 찢다
    나죽못고나강뿐
  • 전체
    오늘
    어제
    • 분류 전체보기 (458)
      • Computer Science (60)
        • Git & Github (4)
        • Network (17)
        • Computer Structure & OS (13)
        • Software Engineering (5)
        • Database (9)
        • Security (5)
        • Concept (7)
      • Frontend (21)
        • React (13)
        • Android (4)
        • iOS (4)
      • Backend (77)
        • Spring Boot & JPA (50)
        • Django REST Framework (14)
        • MySQL (8)
        • Nginx (1)
        • FastAPI (4)
      • DevOps (24)
        • Docker & Kubernetes (11)
        • Naver Cloud Platform (1)
        • AWS (2)
        • Linux (6)
        • Jenkins (0)
        • GoCD (3)
      • Coding Test (112)
        • Solution (104)
        • Algorithm (7)
        • Data structure (0)
      • Reference (134)
        • Effective-Java (90)
        • Pragmatic Programmer (0)
        • CleanCode (11)
        • Clean Architecture (2)
        • Test-Driven Development (4)
        • Relational Data Modeling No.. (0)
        • Microservice Architecture (2)
        • 알고리즘 문제 해결 전략 (9)
        • Modern Java in Action (0)
        • Spring in Action (0)
        • DDD start (0)
        • Design Pattern (6)
        • 대규모 시스템 설계 (6)
        • JVM 밑바닥까지 파헤치기 (4)
      • Service Planning (2)
      • Side Project (5)
      • AI (0)
      • MATLAB & Math Concept & Pro.. (1)
      • Review (18)
      • Interview (2)
      • IT News (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃
  • 공지사항

    • 한동안 포스팅은 어려울 것 같습니다. 🥲
    • N Tech Service 풀스택 신입 개발자가 되었습니다⋯
    • 취업 전 계획 재조정
    • 취업 전까지 공부 계획
    • 앞으로의 일정에 대하여..
  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
나죽못고나강뿐
[Python] 11438 - LCA2 (플래티넘 5)

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.