백준(BOJ) 1033 칵테일 파이썬(Python)

문제 링크

최대공약수(GCD)를 구하기 위해 유클리드 호제법을 사용하는 문제.
일단, 각 재료들간의 관계는 그래프(정확히는 트리)로 표현할 수 있다.
재료 번호가 노드가 되고, 그 사이의 비율관계가 간선이 된다.
이 그래프를 순회하면서, 재료의 비율에 맞게 정답 리스트를 업데이트하면 된다.
이때, 이전에 계산한 값들은 갱신된 값을 반영하지 않고 있는데, 입력 크기가 작으므로 큰 고민 없이 방문한 값들을 순회하며 현 노드에 곱해진 값만큼 곱해서 갱신해주면 된다.
DFS 안에서 리스트 순회를 하는 것이 불편하다면(\(O(V)\)가 곱해지는 셈이므로), 순회하지 않고 최종적으로 구한 마지막 노드의 값에서부터 다시 DFS를 해서(\(O(V)\)가 더해지는 셈이다) 다른 노드의 값을 구해도 상관없긴 할 것이다.

#!python

# a와 b의 gcd를 구함
def gcd(a, b):
    if a < b:
        a, b = b, a
    if not b:
        return a
    return gcd(b, a % b)

n = int(input())
ans = [1] * n
tree = [[] for _ in range(n)]

# 그래프(트리) 형태로 데이터를 만든다
# tree[a]는 a번 노드에서 갈 수 있는 (노드, 비율1, 비율2)의 쌍
for _ in range(n - 1):
    a, b, p, q = map(int, input().split())
    tree[a].append((b, p, q))
    tree[b].append((a, q, p))

# visited 리스트 초기화
visited = [False] * n
visited[0] = True

# qu는 큐
qu = [0]

# DFS
while qu:
    node = qu.pop()
    for succ, v1, v2 in tree[node]:
        if visited[succ]:
            continue
        visited[succ] = True

        # 비율에 기반해서 현재 노드와 다음 노드의 값을 갱신
        temp = ans[node]
        ans[node] *= v1 // gcd(v1, v2 * temp)
        ans[succ] *= ans[node] * v2 // v1
        
        # 현재 노드의 값이 바뀌었기 때문에 이전에 계산한 노드들의 값도 그만큼 증가시켜야 한다
        for i in range(n):
            if i in (node, succ) or not visited[i]:
                continue
            ans[i] *= v1 // gcd(v1, v2 * temp)

        qu.append(succ)

print(*ans)

2024

맨 위로 이동 ↑

2023

세그먼트 트리

개요 선형적인 자료구조에서는 값에 접근하는 데에 \(O(1)\)이면 충분하지만, 대신 부분합을 구하는 데에는 \(O(N)\)이 필요하다. 그렇다면 이 자료구조를 이진 트리로 구성하면 어떨까? 값에 접근하는 데에 걸리는 시간이 \(O(\lg N)\)으로 늘어나지만 대신 부분합을 구하...

벨만-포드 알고리즘

개요 다익스트라 알고리즘과 함께 Single Sourse Shortest Path(SSSP) 문제를 푸는 알고리즘이다. 즉, 한 노드에서 다른 모든 노드로 가는 최단 경로를 구하는 알고리즘이다. 다익스트라 알고리즘보다 느리지만, 음수 가중치 간선이 있어도 작동하며, 음수 가중치 사...

다익스트라 알고리즘

개요 다익스트라 알고리즘은 Single Sourse Shortest Path(SSSP) 문제를 푸는 알고리즘 중 하나이다. 즉, 한 노드에서 다른 모든 노드로 가는 최단 경로를 구하는 알고리즘이다. 단, 다익스트라 알고리즘은 음수 가중치 엣지를 허용하지 않는다. 이 경우에는 벨만-...

맨 위로 이동 ↑