Algorithms · Beginner's Guide

알고리즘, 처음부터 차근차근

기호도 용어도 낯선 상태에서 읽기 시작해도 괜찮다. 각 절은 "이게 무엇을 푸는 알고리즘인가"부터 시작해서 작은 예시로 끝난다.

00

시작하기 전에 · 기호와 용어

본문에서 계속 나오는 기호들을 먼저 풀어둔다. 한 번만 보고 지나가도 뒤가 훨씬 편해진다.

수학 기호

집합 기호

알고리즘 용어


Part I · 기초

1 · 문제와 사례의 구별

Concept

문제(problem)는 일반적인 질문이고, 사례(instance)는 거기에 구체적 입력을 넣은 것이다.

왜 구별해야 하나

같은 알고리즘이라도 어떤 사례가 들어오느냐에 따라 속도가 다르기 때문이다. 예) 삽입 정렬은 이미 정렬된 배열을 주면 빠르지만, 완전히 뒤집힌 배열을 주면 느리다.

풀 수 없는 문제도 있다

"어떤 프로그램이 언젠가 멈출지 판정하라"는 정지 문제(Halting Problem)는 일반적으로 어떤 알고리즘으로도 풀 수 없음이 증명되어 있다. 세상엔 원리적으로 풀 수 없는 문제가 있다는 뜻.

2 · 빅오 표기법

Concept · Ch. 3

"n이 커질 때 알고리즘이 얼마나 빨리 느려지는가?"를 표현하는 도구.

두 알고리즘의 실행 시간이 각각 $n^2$과 $n^3$이라면, n이 아주 커질 때 $n^2$이 훨씬 덜 커지므로 $n^2$ 쪽이 빠르다. 빅오 표기법은 이 "성장 속도"를 비교할 수 있는 형태로 만든 것이다.

세 가지 표기

기호의미말로 하면
$f = O(g)$상한f는 g보다 빨리 자라지 않는다
$f = \Omega(g)$하한f는 g보다 느리게 자라지 않는다
$f = \Theta(g)$양쪽f와 g는 같은 속도로 자란다

정식 정의: $f(n) = O(g(n))$이란, 어떤 양수 c와 $n_0$이 존재해서 $n \ge n_0$일 때 항상 $f(n) \le c \cdot g(n)$인 것.

예시로 감 잡기

3 · 점화식과 재귀 트리

Concept · Ch. 2, 4

재귀 알고리즘의 시간을 계산하는 도구.

점화식이란

자기 자신으로 자기를 정의하는 식. 예) 병합 정렬의 시간:

$T(n) = 2T(n/2) + cn, \quad T(1) = c$

뜻: n을 반으로 쪼개 두 조각으로 재귀 호출한 뒤(2T(n/2)), 합치는 데 cn 시간이 든다.

재귀 트리로 풀기

각 단계를 트리로 펼쳐보자.

레벨 0:          cn                       (합: cn)
레벨 1:       cn/2  cn/2                  (합: cn)
레벨 2:    cn/4 cn/4 cn/4 cn/4            (합: cn)
  ...
레벨 log n:  n개의 리프, 각 c씩          (합: cn)

각 레벨의 총 비용이 cn으로 일정하고, 레벨 수는 $\log n + 1$이다. 따라서:

$T(n) = cn \cdot (\log n + 1) = \Theta(n \log n)$
Tip
시험에서 점화식이 나오면 공식을 외우기보다 재귀 트리를 직접 그리는 쪽이 안전하다.

Part II · 정렬

4 · 삽입 정렬

Insertion Sort · Ch. 2

무엇을 푸나 — 숫자 배열을 작은 순서(또는 큰 순서)로 재배치한다.

일상 비유

손에 든 카드를 정리할 때 사람이 자연스럽게 쓰는 방식이다. 새 카드를 한 장씩 보면서, 이미 정리된 앞부분에 적절한 자리를 찾아 끼워 넣는다.

알고리즘

INSERTION-SORT(A)
  for j = 2 to A.length
    key = A[j]
    i = j - 1
    while i > 0 and A[i] > key
      A[i+1] = A[i]   // 큰 원소를 한 칸 뒤로
      i = i - 1
    A[i+1] = key   // 빈 자리에 key

예시: [5, 2, 4, 6, 1, 3]

단계상태
시작[5 | 2, 4, 6, 1, 3]
2 삽입[2, 5 | 4, 6, 1, 3]
4 삽입[2, 4, 5 | 6, 1, 3]
6 삽입[2, 4, 5, 6 | 1, 3]
1 삽입[1, 2, 4, 5, 6 | 3]
3 삽입[1, 2, 3, 4, 5, 6]

시간 복잡도

데이터가 작거나 거의 정렬돼 있으면 실제로 빠르다. 하지만 일반적으로는 느린 축에 든다.

5 · 병합 정렬

Merge Sort · Ch. 2

무엇을 푸나 — 정렬. 단, 최악의 경우에도 $\Theta(n \log n)$을 보장한다.

핵심 아이디어: 쪼개서 각자 정렬 후 합치기

  1. 분할: 배열을 반으로 나눈다.
  2. 정복: 두 절반을 재귀적으로 각각 정렬한다.
  3. 결합(merge): 정렬된 두 절반을 차례로 비교하며 하나로 합친다.

예시: [5, 2, 4, 6, 1, 3, 2, 6]

분할:  [5,2,4,6,1,3,2,6]
      → [5,2,4,6]  [1,3,2,6]
      → [5,2] [4,6] [1,3] [2,6]
      → [5][2] [4][6] [1][3] [2][6]

결합:  [2,5] [4,6] [1,3] [2,6]
      → [2,4,5,6]  [1,2,3,6]
      → [1,2,2,3,4,5,6,6]

결합 과정 (핵심)

[2,5]와 [4,6]을 합칠 때: 양쪽 맨 앞을 비교 → 작은 걸 뽑기. "2 vs 4" → 2, "5 vs 4" → 4, "5 vs 6" → 5, 남은 6. 결과 [2,4,5,6].

시간

점화식 $T(n) = 2T(n/2) + \Theta(n)$ → $\Theta(n \log n)$.

어디가 비싼가? 대부분의 일이 합치는(merge) 단계에서 일어난다. 이 점에서 퀵 정렬과 대비된다(퀵은 분할에서 일한다).

6 · 힙 정렬

Heapsort · Ch. 6

무엇을 푸나 — 정렬. 힙(heap)이라는 자료구조의 힘을 빌린다.

힙이란

Max-heap: "부모 ≥ 자식"이라는 규칙을 지키는 이진 트리. 맨 위(루트)에 항상 최댓값이 온다. 모양은 "거의 꽉 찬" 이진 트리 — 마지막 줄만 왼쪽부터 일부 채워져 있고 나머지는 다 차 있다.

배열로 저장: 인덱스 i의 부모는 $i/2$, 자식은 2i와 2i+1.

세 가지 함수

① Max-Heapify(A, i) — i와 자식들 중 가장 큰 값을 i로 올린다. 바꾼 자리에서 재귀. 시간 $O(\log n)$.

② Build-Max-Heap(A) — 배열 전체를 힙으로 만든다. 중간부터 거꾸로 Heapify.

BUILD-MAX-HEAP(A)
  for i = ⌊A.length/2downto 1
    MAX-HEAPIFY(A, i)

시간 $O(n)$ — 겉보기엔 $O(n \log n)$ 같지만, 밑에 있는 노드가 훨씬 많고 그들에겐 할 일이 적어서 총합이 선형으로 떨어진다.

③ Heapsort — 루트(최댓값)를 배열 끝으로 보낸 뒤, 힙 크기를 줄이고 다시 Heapify. n−1번 반복.

비유

스포츠 토너먼트를 떠올리면 된다. 매번 1등을 뽑아 빼고, 나머지로 다시 토너먼트를 돌린다. 차이점은 매번 새로 토너먼트를 짜지 않고 트리 한 줄만 수선한다는 것.

시간

전체: $O(n) + (n-1)\cdot O(\log n) = O(n \log n)$.

7 · 퀵 정렬

Quicksort · Ch. 7

무엇을 푸나 — 정렬. 실무에서 가장 많이 쓰이는 정렬.

핵심 아이디어: 기준 세우고 양쪽으로 가르기

  1. 배열에서 피벗(기준값) 하나 고른다. 보통 맨 뒤.
  2. 피벗보다 작은 것은 왼쪽, 큰 것은 오른쪽으로 보낸다 → 피벗은 정확히 자기 자리로 간다.
  3. 왼쪽, 오른쪽 각각에 대해 같은 일을 재귀적으로.

Partition 과정

PARTITION(A, p, r)
  x = A[r]               // 피벗 = 맨 뒤
  i = p - 1
  for j = p to r-1
    if A[j] <= x
      i = i + 1
      swap(A[i], A[j])
  swap(A[i+1], A[r])
  return i+1           // 피벗의 새 위치

예시: [2, 1, 3, 4, 10, 12, 6, 9, 5] — 피벗 5

왼쪽으로 가는 것: 2, 1, 3, 4. 오른쪽으로 가는 것: 10, 12, 6, 9. 결과: [2,1,3,4, 5, 10,12,6,9]. 5가 자기 자리.

복잡도는 피벗 운에 달렸다

최악을 피하려고 피벗을 무작위로 고르는 게 무작위 퀵 정렬(10절).


Part III · 확률적 분석

8 · 고용 문제

Hiring Problem · Ch. 5

무엇을 푸나 — "평균적으로 몇 번이나 일어나는가?"를 계산하는 연습 문제.

상황

지원자 n명을 한 명씩 면접한다. 지금까지 본 사람 중 가장 뛰어난 사람이 나오면 고용한다 (이전 사람은 해고). 지원자 순서는 완전히 무작위다. 평균 몇 번 고용할까?

직관은 왜 틀리는가

"매번 1등이 바뀌어서 n번쯤 고용할 것 같다"고 생각하기 쉽지만 틀리다. 답은 $O(\log n)$이다.

풀이 아이디어: 0-1 변수로 쪼개기

$X_i = $ "i번째 사람을 고용하면 1, 아니면 0"으로 정의. 그러면 총 고용 수 $X = X_1 + X_2 + \cdots + X_n$.

i번째 사람을 고용하려면 앞 i명 중 1등이어야 한다. 순서가 무작위이니 확률은 $1/i$.

$E[X] = \sum_{i=1}^{n} \frac{1}{i} = H_n = \ln n + O(1) = O(\log n)$

$H_n$은 조화수라고 부르는 유명한 수열이다.

9 · 지시 확률 변수

Indicator Random Variable

무엇을 푸나 — 복잡한 기댓값을 쉽게 계산하는 일반적 기법.

정의

어떤 사건 A에 대해 "A가 일어나면 1, 아니면 0"인 변수를 $I\{A\}$로 쓴다.

그 기댓값은 바로 그 사건이 일어날 확률:

$E[I\{A\}] = \Pr(A)$

기댓값의 선형성

$E[X_1 + X_2 + \cdots + X_n] = E[X_1] + E[X_2] + \cdots + E[X_n]$

중요: 변수들이 독립이 아니어도 성립. 이게 굉장히 편리하다.

작은 예

공정한 동전을 n번 던졌을 때 앞면이 나오는 횟수의 기댓값은? $X_i = $ "i번째가 앞면이면 1"로 두면 $E[X_i] = 1/2$, 총 $E[X] = n/2$.

10 · 무작위 퀵 정렬의 O(n log n) 증명

Ch. 7 · 2025 여름 출제

무엇을 푸나 — "무작위로 피벗을 고르면 평균 $O(n \log n)$"임을 증명.

전제

증명 단계

  1. 정렬 후 순서대로 원소를 $z_1, z_2, \ldots, z_n$이라 부른다 ($z_i$ = i번째로 작은 값).
  2. $X_{ij}$ = "$z_i$와 $z_j$가 비교되면 1, 아니면 0"로 정의. 총 비교 $X = \sum_{i
  3. 핵심 관찰: 퀵 정렬에서 두 원소가 직접 비교되는 건 둘 중 하나가 피벗일 때뿐이다. 집합 $Z_{ij} = \{z_i, z_{i+1}, \ldots, z_j\}$에서 가장 먼저 피벗으로 뽑히는 원소가 $z_i$나 $z_j$여야만 둘이 비교된다. 중간의 원소가 먼저 피벗이 되면 두 원소는 서로 다른 반쪽으로 갈라져 영영 만나지 않는다.
  4. $|Z_{ij}| = j-i+1$이고 균등 확률이므로:
    $E[X_{ij}] = \Pr(z_i \text{ 또는 } z_j\text{가 먼저 피벗}) = \dfrac{2}{j-i+1}$
  5. 선형성과 변수 치환($k = j-i$)으로 합산:
    $E[X] = \sum_{i=1}^{n-1}\sum_{k=1}^{n-i}\frac{2}{k+1} < \sum_{i=1}^{n-1} O(\log n) = O(n \log n)$
답안 작성 팁
단계 3의 "가장 먼저 피벗이 되는 원소" 설명이 가장 자주 빠진다. 이게 있어야 $2/(j-i+1)$이 정당화된다.

Part IV · 동적 계획법

11 · DP의 두 가지 특성

Ch. 15

무엇을 푸나 — 최적화 문제를 "작은 부분 문제를 풀어 저장해두고 재활용"하는 방식.

DP가 작동하려면 문제가 다음 두 성질을 가져야 한다.

① 최적 부분 구조 (Optimal Substructure)

전체 최적해가 부분 문제들의 최적해로 이루어짐.

② 겹치는 부분 문제 (Overlapping Subproblems)

같은 부분 문제를 반복해서 풀어야 함 → 표에 답을 저장해 재활용.

DP vs 탐욕 비교

특성의미필요한 기법
Optimal substructure최적해가 부분해의 최적해로DP, Greedy 둘 다
Overlapping subproblems같은 부분 문제 반복DP
Greedy choice순간 최선이 전체 최적Greedy

"잘라 붙이기" 증명

최적 부분 구조를 증명할 때 쓰는 표준 기법: "부분해가 최적이 아니라면 더 좋은 해로 잘라 붙이면 전체가 더 좋아지고, 이건 원래 해가 최적이라는 가정에 모순."

12 · 행렬 연쇄 곱셈

Matrix Chain · Ch. 15 · 3회 연속 출제

무엇을 푸나 — 여러 행렬을 곱할 때 곱셈 횟수가 최소인 괄호 조합을 찾는다.

왜 순서가 중요한가

행렬 곱은 결합법칙이 성립한다 ($A(BC) = (AB)C$). 그런데 비용은 같지 않다. $p \times q$ 행렬과 $q \times r$ 행렬을 곱하면 스칼라 곱셈은 $p \cdot q \cdot r$번 필요하다. 순서에 따라 비용이 크게 달라진다.

문제 (시험 단골)

점화식

$m[i,j]$ = $A_i$부터 $A_j$까지 곱하는 최소 비용.

$m[i,j] = \min_{i \le k < j}\{m[i,k] + m[k+1,j] + p_{i-1} p_k p_j\}$

해석: 둘로 가르는 모든 방법을 시도해서 제일 싼 걸 고른다.

표를 대각선 순서로 채움

길이 2

길이 3

길이 4

최종 표

m[i,j]j=1j=2j=3j=4
i=10243648
i=202442
i=3024
i=40

최적 괄호화: ((A₁(A₂A₃))A₄). 최소 비용 48.

13 · 최장 공통 부분수열 (LCS)

Ch. 15

무엇을 푸나 — 두 문자열 X, Y에서 순서를 지키며 공통으로 뽑을 수 있는 가장 긴 문자열.

어디에 쓰이나

점화식

$c[i,j]$ = X의 앞 i글자와 Y의 앞 j글자의 LCS 길이.

$c[i,j] = \begin{cases} 0 & i=0 \text{ 또는 } j=0 \\ c[i-1,j-1] + 1 & x_i = y_j \\ \max(c[i-1,j],\, c[i,j-1]) & x_i \ne y_j \end{cases}$

해석: 마지막 글자가 같으면 "+1", 다르면 한쪽을 포기하고 큰 값 쪽을 선택.

예시: X = GTACCGTCA, Y = TCGA

GTACCGTCA
0000000000
T0011111111
C0011222222
G0111223333
A0112223334

LCS 길이 4, 역추적하면 TCGA.

14 · 0/1 배낭 문제

Knapsack · Ch. 15

무엇을 푸나 — 용량 W짜리 배낭에 물건을 넣어 총 가치를 최대화. 각 물건은 통째로 넣거나 안 넣거나.

어디에 쓰이나

최적 부분 구조 증명

최적해 S에서 물건 j에 대해 두 경우로 나눈다.

분할(fractional) 배낭과의 차이

물건을 쪼갤 수 있다면 "가치/무게 비율이 높은 순서로" 채우는 탐욕이 맞다. 그러나 0/1 배낭은 탐욕이 통하지 않는다. 반드시 DP가 필요.

반례 감각
용량 10, 물건 A(무게 6, 가치 11), B(무게 5, 가치 8), C(무게 5, 가치 8). 비율이 가장 큰 A를 먼저 넣으면 남은 용량 4로 아무것도 못 넣어 총 11. 그런데 B+C면 16. 탐욕이 지는 상황.

Part V · 탐욕 알고리즘

15 · 활동 선택

Activity Selection · Ch. 16

무엇을 푸나 — 서로 시간이 겹치지 않는 활동을 최대한 많이 고른다.

실생활 비유

회의실 하나에 예약 신청이 여러 건 들어왔다. 시간이 겹치지 않도록 최대한 많은 예약을 받으려면?

탐욕 전략

종료 시간이 가장 이른 활동부터 고른다. 시작 시간이 이른 순이 아니다.

왜 맞는가 (직관)

빨리 끝나는 걸 먼저 고르면 남은 시간 자원이 최대가 된다. 그래서 뒤에 더 많은 활동을 끼울 수 있다.

증명 (교환 논법)

  1. 활동을 종료 시간 순 정렬: $f_1 \le f_2 \le \cdots \le f_n$.
  2. 임의의 최적해 A를 잡고, 그 첫 원소를 k라 하자.
  3. k = 1이면 끝. 아니면 $A' = (A \setminus \{k\}) \cup \{1\}$을 만든다.
  4. $f_1 \le f_k$이므로 1은 A의 나머지와 겹치지 않음. |A'| = |A| → A'도 최적해. 활동 1 포함. ∎

작은 예시

활동a1a2a3a4a5
시작 s13053
종료 f45679

종료순으로 고르면 a1(끝 4) → a4(끝 7). 2개 선택.

16 · 매트로이드

Matroid · Ch. 16.4

무엇을 푸나 — "어떤 문제가 탐욕으로 풀리나?"에 대한 구조적 답.

정의

쌍 $M = (S, I)$가 매트로이드이려면:

  1. S는 비어있지 않은 유한 집합.
  2. I는 S의 부분집합 모음으로 두 조건 만족:
    • 상속(Hereditary): $X \in I,\ Y \subseteq X \Rightarrow Y \in I$. (독립 집합의 부분집합도 독립)
    • 교환(Exchange): $X, Y \in I,\ |X| > |Y| \Rightarrow$ 어떤 $a \in X \setminus Y$에 대해 $Y \cup \{a\} \in I$. (큰 쪽에서 하나를 빌려 작은 쪽에 넣어도 독립)

핵심 정리

문제 구조가 매트로이드 ⇒ 탐욕으로 풀 수 있다.

역은 성립하지 않는다. 활동 선택은 매트로이드가 아니지만 탐욕으로 풀린다.

예시: Graphic Matroid

무방향 그래프 $G = (V, E)$에서 $S = E$, $I = \{A \subseteq E : A \text{가 사이클 없음}\}$(숲, forest). 이게 매트로이드임을 증명할 수 있다.

17 · 단위 작업 스케줄링

Ch. 16.5 · 5회 출제

무엇을 푸나 — 각 작업이 1시간씩 걸리고 마감과 벌점이 있을 때, 총 벌점 최소화.

상황

매트로이드 정의

상속 증명

$A \in I$이고 $B \subseteq A$면, A의 스케줄에서 B 외 작업을 빼면 된다. B의 작업은 앞당겨져서 오히려 여유로움. ∎

교환 증명 (핵심)

보조 정리: $X \in I$이면 X의 작업을 마감 순으로 정렬해 슬롯 1, 2, ...에 배치하면 유효 스케줄.

A, B가 각각 마감 순으로 정렬 배치됐다고 하자. $|A| > |B|$니까 A에만 있는 작업 중 가장 늦은 시각 t에 배치된 a가 존재한다. $t > |B|$이고 $d_a \ge t > |B|$. 그러면 a를 B의 (|B|+1)번째 슬롯에 넣어도 마감 안전. ∎

답안 팁
"마감 순 정렬이 유효 스케줄이다"는 보조 정리를 명시적으로 쓰는 게 중요.

Part VI · 무작위 알고리즘

18 · Freivalds 알고리즘

HW1 Q2

무엇을 푸나 — "$AB = C$인지?"를 실제로 AB를 계산하지 않고 확률적으로 검증.

왜 필요한가

행렬 곱 검증을 직접 하면 $O(n^3)$(Strassen이어도 $O(n^{2.81})$). Freivalds는 $O(n^2)$.

알고리즘

  1. $x \in \{0, 1\}^n$을 균등 무작위로 고른다 (각 성분이 0 또는 1).
  2. $ABx$와 $Cx$를 비교. 다르면 NO, 같으면 YES.

$Bx$(벡터-행렬 곱)는 $O(n^2)$, 그 결과에 $A$ 곱도 $O(n^2)$. 총 $O(n^2)$.

오류 분석

$AB = C$면 항상 YES (정확). 문제는 $AB \ne C$인데 YES가 나올 확률.

$\Pr(ABx = Cx \mid AB \ne C) \le \dfrac{1}{2}$

증명 요약

  1. $D = AB - C \ne 0$. 적어도 한 성분이 0 아님.
  2. 일반성을 잃지 않고 첫 행의 앞쪽에 $d_1, d_2, \ldots, d_k$ (모두 0 아님), 뒤는 0이라고 가정.
  3. $Dx = 0$이려면 특히 $d_1 x_1 + d_2 x_2 + \cdots + d_k x_k = 0$.
  4. 정리: $x_1 = (-d_2 x_2 - \cdots - d_k x_k)/d_1$.
  5. $x_2, \ldots, x_k$를 먼저 뽑고 $x_1$을 뽑는다고 하면, 우변은 어떤 고정값 $v$.
  6. $x_1 \in \{0,1\}$ 균등이니 $x_1 = v$일 확률은 최대 1/2. ∎

k번 반복해 모두 YES일 때만 YES라 하면 오답 확률 $(1/2)^k$. 20번이면 0.0001% 이하.

19 · Tutte 행렬

비교재

무엇을 푸나 — 이분 그래프에 완벽 매칭(모두가 짝이 있는 매칭)이 있는지 확률적으로 판정.

어디에 쓰이나

학생-과제 배정, 직원-프로젝트 배정처럼 "양쪽이 같은 수고 모두에게 1:1 매칭이 가능한가?"를 묻는 상황.

Tutte 행렬

이분 그래프 $G = (L \cup R, E)$, $|L|=|R|=n$. $n \times n$ 행렬 T:

Tutte 정리

완벽 매칭 존재 ⇔ T의 행렬식이 다항식으로서 항등적으로 0이 아님.

알고리즘

  1. 각 $x_{ij}$에 $\{1, \ldots, m^2\}$에서 무작위 정수 대입 (m = 간선 수).
  2. 행렬식 계산.
  3. 0 아니면 YES, 0이면 NO.

False negative 가능(매칭은 있는데 우연히 0이 나옴). 여러 번 반복으로 확률 감소.

20 · 이진 결정 트리 동치 판정

비교재

무엇을 푸나 — 두 이진 결정 트리가 같은 불리언 함수인지 확률적으로 판정.

이진 결정 트리

아이디어

  1. 소수 $p > 2n$을 고르고, 각 변수에 $\{0, \ldots, 2n-1\}$에서 무작위 수 $i$ 할당(참일 때 값).
  2. 거짓일 때 값은 $1 - i \pmod p$.
  3. T로 끝나는 모든 경로의 변수 값들을 곱한 뒤 모두 더해 "서명"을 만든다(mod p).
  4. 두 트리의 서명이 같으면 YES.

False positive 가능. 결정론적 다항 시간 알고리즘이 존재하는지 아직 알려지지 않은 문제를 무작위로 현실적으로 푼 사례.


Part VII · 그래프

21 · 연결 컴포넌트

Connected Components · Ch. 21

무엇을 푸나 — 그래프에서 서로 연결된 정점 그룹들을 찾아낸다.

어디에 쓰이나

Disjoint Set 자료구조

알고리즘

CONNECTED-COMPONENTS(G)
  for each vertex v ∈ G.V
    MAKE-SET(v)
  for each edge (u,v) ∈ G.E
    if FIND-SET(u) ≠ FIND-SET(v)
      UNION(u, v)

rank + path compression 최적화로 총 시간 $O((V+E)\alpha(V))$, 사실상 선형.

22 · Warshall 알고리즘

이행적 폐쇄

무엇을 푸나 — 방향 그래프에서 모든 쌍 (i, j)에 대해 "i에서 j로 가는 경로가 있나?"를 0/1로.

어디에 쓰이나

"A 공항에서 B 공항까지 비행 노선을 갈아타며 갈 수 있는가?" 같은 도달 가능성 문제.

점화식

$r^{(k)}[i][j]$ = "중간 정점으로 {1, …, k}만 허용했을 때 $i \to j$ 경로 존재".

$r^{(k)}[i][j] = r^{(k-1)}[i][j] \lor (r^{(k-1)}[i][k] \land r^{(k-1)}[k][j])$

해석: k를 안 지나도 갈 수 있거나, k를 지나서 갈 수 있거나.

시간 $\Theta(V^3)$. 연산 구조: $\{0,1\}$에 AND/OR.

23 · Floyd 알고리즘

모든 쌍 최단 거리

무엇을 푸나 — 가중 방향 그래프에서 모든 쌍 (i, j) 사이의 최단 거리.

어디에 쓰이나

"모든 도시 쌍 사이의 최단 경로"가 필요한 교통망 계산, 경기장 좌석 거리표 등.

점화식

$d^{(k)}[i][j] = \min\bigl(d^{(k-1)}[i][j],\ d^{(k-1)}[i][k] + d^{(k-1)}[k][j]\bigr)$

구조가 Warshall과 쌍둥이. 값만 0/1 대신 거리, AND/OR 대신 MIN/PLUS.

시간 $\Theta(V^3)$.

24 · Dijkstra 알고리즘

단일 출발지 최단 거리

무엇을 푸나 — 한 출발 정점에서 다른 모든 정점까지의 최단 거리. 모든 간선 가중치가 0 이상일 때만.

어디에 쓰이나

내비게이션, 지도 앱, 네트워크 라우팅.

구조

  1. $D[s] = 0$, 나머지 정점은 $\infty$.
  2. min-priority queue에 모든 정점 넣기.
  3. 큐가 빌 때까지:
    • D 값 최소인 $w$ 꺼냄.
    • $w$의 이웃들에 대해 "w 경유해 가면 짧아지나?" 검사해 D 갱신.

시간 $O((V+E)\log V)$ (이진 힙 기준).

세 알고리즘의 공통 구조
Warshall, Floyd, Dijkstra는 (값 집합, 두 연산)이라는 같은 뼈대에서 다른 재료를 끼운 것이다. Warshall은 ({0,1}, AND, OR), Floyd/Dijkstra는 (비음 실수 ∪ {∞}, MIN, PLUS).

Part VIII · 과제 문제 복기

25 · 과제 Q3 · X(n) 시간 복잡도

X(n)
  r = 0
  for i = 1 to n-1 do
    for j = i+1 to n do
      for k = 1 to j do
        r = r + 1
  return r

풀이

  1. 가장 안쪽 루프는 j번 실행 → r에 j 추가.
  2. 중간 루프: $\sum_{j=i+1}^{n} j = \frac{n(n+1)}{2} - \frac{i(i+1)}{2}$.
  3. 바깥 루프까지 합: $$r = \sum_{i=1}^{n-1}\!\left[\frac{n(n+1)}{2} - \frac{i(i+1)}{2}\right] = \frac{n(n+1)(n-1)}{2} - \frac{1}{2}\!\sum_{i=1}^{n-1}\!i^2 - \frac{1}{2}\!\sum_{i=1}^{n-1}\!i$$
  4. $\sum i^2$, $\sum i$ 공식 대입 후 $\frac{n(n-1)}{2}$로 묶으면:
$r = \dfrac{n(n-1)(n+1)}{3} = \Theta(n^3)$

26 · 과제 Q4 · 점화식 풀이

$T(1) = 1,\ T(n) = 3T(n-1) + 2$ ($n \ge 2$). 닫힌 형태로 구하라.

반복 대입

패턴: $T(n) = 3^{n-1} + (3^{n-2} + \cdots + 3^0) \cdot 2 = 3^{n-1} + (3^{n-1} - 1)$.

$T(n) = 2 \cdot 3^{n-1} - 1$

27 · 재귀 함수 trace

A = [3, 1, 2], n = 3. Y(1)의 실행 결과는?

Y(i)
  if i == n then print A
  else
    Y(i+1)
    for j = i+1 to n
      swap(A[i], A[j])
      Y(i+1)
      swap(A[i], A[j])   // 원복

의도: 배열의 모든 순열을 생성.

Trace

  1. Y(1): A = [3,1,2]. Y(2) 호출
    • Y(3): print [3,1,2]
    • j=3: swap → [3,2,1], Y(3) print [3,2,1], 원복 → [3,1,2]
  2. j=2: swap(A[1],A[2]) → [1,3,2], Y(2)
    • Y(3): print [1,3,2]
    • j=3: swap → [1,2,3], Y(3) print [1,2,3], 원복 → [1,3,2]
    원복 → [3,1,2]
  3. j=3: swap(A[1],A[3]) → [2,1,3], Y(2)
    • Y(3): print [2,1,3]
    • j=3: swap → [2,3,1], Y(3) print [2,3,1], 원복 → [2,1,3]
    원복 → [3,1,2]

출력: [3,1,2], [3,2,1], [1,3,2], [1,2,3], [2,1,3], [2,3,1] — 총 3! = 6개.


Part IX · 체크리스트

28 · 시험 당일 확인 목록

외워둬야 할 것

증명에서 잘 빠뜨리는 부분

답안 작성 요령

알고리즘 시험은 암기가 아니라 구조를 보는 시험이다.
"왜 이 기법이 여기서 작동하는가"를 말로 설명할 수 있으면 비슷한 신규 문제도 풀린다.