이산수학 노트

증명, 그래프, 세기, 확률, 점화식 — 컴퓨터과학을 떠받치는 다섯 기둥을 한 권에.

Part I

증명
명제, 귀납, 상태기계, 재귀, 무한집합 — "왜 이 알고리즘이 옳은가?"의 도구함.

Part II

구조
정수론과 그래프. RSA, 위상정렬, 4색 정리, 다면체. 이산 세계의 골격.

Part III

세기
합과 점근, 카운팅, 생성함수. 알고리즘 분석의 산수.

Part IV

확률
표본공간부터 임의 보행까지. 무작위 알고리즘과 데이터 과학의 뼈대.

Part V

점화식
분할정복부터 마스터 정리까지. 재귀의 비용을 손에 쥐는 법.

왼쪽 사이드바에서 챕터를 고르거나, 검색창에 키워드를 입력해 보세요. 예: 증명, RSA, 몬티홀, 피보나치.

PART I — 증명

1 증명이란 무엇인가 What is a Proof?

수학에서 "맞다"는 말은 어떤 의미일까요? 과학자는 실험으로, 법정은 증거로, 친구끼리는 그냥 우기는 걸로 무언가를 "증명"한다고 말합니다. 이 챕터에서는 수학에서 통용되는 증명, 즉 누구도 빠져나갈 수 없도록 논리만으로 진리를 확립하는 방법을 배웁니다. 이산수학을 처음 만나는 여러분에게 가장 먼저 필요한 도구이자, 앞으로 모든 챕터의 공용어가 되는 내용입니다.

1.1 명제 Propositions

증명을 이야기하기 전에 먼저 "무엇을" 증명하는지부터 분명히 해야 합니다. 수학에서 증명의 대상은 항상 명제(proposition)입니다. 명제란 참(true)인지 거짓(false)인지가 분명히 정해지는 평서문을 말합니다. 명령문이나 의문문, 감탄문은 명제가 아닙니다. "문 좀 닫아줘"는 참도 거짓도 아니니까요.

정의 1.1.1 (명제)

참(T) 또는 거짓(F) 둘 중 하나의 진릿값을 갖는 평서문을 명제라고 합니다.

예제 1.1.2

다음 문장 중 명제는 어떤 것일까요?

  • (a) \( 2 + 3 = 5 \). — 명제(참).
  • (b) 모든 짝수는 두 소수의 합으로 쓸 수 있다. — 명제(아직 인류가 참/거짓을 모르지만, 문장 자체는 진릿값을 가짐. 이게 그 유명한 골드바흐 추측이에요).
  • (c) \( x + 1 = 2 \). — 명제 아님. \( x \)가 무엇인지 모르면 참/거짓을 정할 수 없습니다.
  • (d) "이 문장은 거짓이다." — 명제 아님. 참이라 가정해도 거짓이고, 거짓이라 가정해도 참이라 진릿값이 정해지지 않아요.
  • (e) 라면이 짜다. — 일상에서 명제처럼 보이지만, 기준이 사람마다 달라서 수학에서는 명제로 다루지 않습니다.

여러 명제를 "그리고", "또는", "아니다", "~이면 ~이다" 같은 연결사로 묶으면 합성 명제(compound proposition)가 됩니다. 예컨대 \( P \)가 "비가 온다", \( Q \)가 "땅이 젖는다"라면, \( P \implies Q \)는 "비가 오면 땅이 젖는다"라는 새로운 명제입니다. 우리는 곧 이런 연결사들을 도구처럼 다루게 될 거예요.

노트

일상에서 우리가 "명제"라고 부르는 많은 문장들("이 영화 재밌어", "오늘 날씨가 좋네")은 사실 수학적 의미의 명제는 아닙니다. 수학적 명제는 평가 기준이 명확하고, 누가 봐도 동일한 결론에 이를 수 있어야 합니다. 이 엄격함이 답답해 보일 수 있지만, 이게 바로 수학이 "다툴 일이 없는" 학문이 되는 이유예요.

1.2 술어 Predicates

방금 본 \( x + 1 = 2 \)는 명제가 아니었습니다. 그런데 변수 \( x \)에 구체적인 값을 넣으면 명제가 되지요. 이렇게 변수가 들어가서 그 변수의 값에 따라 진릿값이 달라지는 문장을 술어(predicate)라고 부릅니다. 보통 \( P(x) \), \( Q(n) \) 같은 표기를 씁니다.

정의 1.2.1 (술어)

한 개 이상의 변수에 의존하는 문장으로, 각 변수에 구체적인 값을 대입할 때마다 명제가 되는 것을 술어라고 합니다.

예제 1.2.2

\( P(n) \)을 "\( n^2 + 1 \)은 짝수이다"로 정의해 봅시다.

  • \( P(1) \): \( 1^2 + 1 = 2 \), 짝수. 참.
  • \( P(2) \): \( 2^2 + 1 = 5 \), 홀수. 거짓.
  • \( P(3) \): \( 3^2 + 1 = 10 \), 짝수. 참.

패턴이 보이나요? \( n \)이 홀수일 때 \( P(n) \)이 참인 것 같죠. 이것을 모든 홀수에 대해 보이려면 곧 배울 일반적 증명 기법이 필요합니다.

술어가 중요한 이유는, 수학의 거의 모든 흥미로운 주장이 "모든 \( n \)에 대해 \( P(n) \)이 성립한다" 또는 "어떤 \( n \)이 존재해서 \( P(n) \)이 성립한다" 형태이기 때문입니다. 이 두 가지를 각각 전칭(universal) 양화와 존재(existential) 양화라고 부르고, 기호로 \( \forall n,\ P(n) \), \( \exists n,\ P(n) \)이라 씁니다. 양화 기호의 자세한 사용법은 다음 챕터에서 다룹니다. 지금은 술어가 명제의 "변수 버전"이라는 것만 기억하면 충분해요.

1.3 공리적 방법 The Axiomatic Method

"증명한다"는 게 도대체 무엇일까요? 머리에 떠오르는 그럴듯한 설명을 하는 것? 그림을 그려 보는 것? 수많은 예를 확인하는 것? 셋 다 영감을 주지만, 셋 다 수학적 증명은 아닙니다. 수학에서 증명이란 이미 받아들인 사실들로부터 논리적으로 새 사실을 이끌어내는 과정입니다.

그러면 그 "이미 받아들인 사실"은 어디서 올까요? 끝없이 거슬러 올라갈 수는 없으니, 어딘가에서 멈춰야 합니다. 그 출발점을 공리(axiom)라고 부릅니다. 공리는 증명 없이 참이라고 합의하는 명제입니다. 그리고 공리로부터 논리만 사용해 증명한 명제를 정리(theorem)라 부르고, 그 과정 자체가 증명(proof)입니다.

정의 1.3.1 (공리적 방법)

몇 개의 공리에서 출발해, 오직 논리적 추론으로 새로운 정리를 만들어 가는 수학 작업의 표준 방식을 공리적 방법(axiomatic method)이라 합니다.

이 사고방식은 기원전 300년경 유클리드(Euclid)의 『원론(Elements)』에서 시작되었습니다. 유클리드는 다섯 개의 공준과 몇 개의 공통 관념에서 출발해 평면기하 전체를 쌓아 올렸어요. 2200년이 지난 후 힐베르트(Hilbert)는 유클리드의 빈틈을 메워 더 엄밀한 공리계를 제시했고, 20세기 들어 페아노(Peano), 체르멜로–프렝켈(ZF) 같은 산술/집합론 공리계가 자리를 잡았습니다.

노트

공리는 "당연히 참인 자명한 진리"가 아닙니다. 그저 게임의 규칙처럼 우리가 함께 쓰자고 약속한 시작점일 뿐이에요. 공리를 다르게 잡으면 다른 수학이 나옵니다. 평행선 공리를 살짝 바꾸면 비유클리드 기하가 태어나는 것처럼요.

1.4 우리의 공리들 Our Axioms

이 책에서는 공리계를 처음부터 모두 형식적으로 까는 대신, 학부 1학년 수준의 수학에서 자연스럽게 사용하는 표준 사실들을 공리로 받아들이겠습니다. 즉, 다음과 같은 것들이에요.

  • 산술 공리: 정수, 유리수, 실수의 사칙연산 법칙 — 결합법칙, 교환법칙, 분배법칙, \( 0, 1 \)의 항등 성질, 역원의 존재 등.
  • 순서 공리: 실수의 \( < \) 관계가 가지는 추이성과 삼분법.
  • 집합론의 기초: 합집합, 교집합, 부분집합, 빈집합 같은 개념과 그 기본 성질.
  • 자연수의 잘 정렬성: 자연수의 공집합이 아닌 부분집합은 항상 최소 원소를 가진다 (수학적 귀납법의 기반).

이 공리들은 너무 친숙해서 "굳이 공리라고 부를 필요가 있나?" 싶을 정도지만, 정확히 그 친숙함이 함정이기도 합니다. 한 단계 한 단계의 추론이 정말로 이런 공리만 쓰는지 자기 자신에게 묻는 습관을 들여야 해요.

잠깐, 공리가 거짓이면?

공리계 안에 모순이 숨어 있다면 그 안에서는 어떤 명제도 "증명"할 수 있게 됩니다. 거짓에서는 무엇이든 따라 나오니까요. 그래서 공리의 일관성(consistency)을 확신하는 일은 매우 중요합니다. 다만 괴델의 제2 불완전성 정리가 알려주듯, 충분히 강한 공리계는 자기 자신의 일관성을 자기 안에서 증명할 수 없어요. 다행히 우리가 쓰는 공리계는 수천 년의 사용 경험 속에서 모순이 발견된 적 없으므로, 안심하고 사용해도 됩니다.

예제 1.4.1 (잘못된 공리, 잘못된 정리)

"모든 말은 같은 색이다"라는 우스개 정리가 있습니다. 어떤 책에서는 "말 \( n \)마리 무리에서는 모든 말의 색이 같다"를 \( n \)에 대한 귀납으로 증명하려다 \( n=1 \)에서 \( n=2 \)로 넘어가는 단계에서 공리 아닌 것을 슬쩍 가정해 엉터리 결론에 이릅니다. 시작점이 잘못되거나 한 줄이라도 정당하지 못한 추론이 끼면, 결과는 멀쩡해 보여도 무너집니다. 우리가 받아들이는 공리가 무엇인지를 분명히 의식하는 일이 중요한 이유예요.

1.5 함의 증명 Proving an Implication

가장 흔히 마주치는 명제 형태가 \( P \implies Q \), 즉 "\( P \)이면 \( Q \)이다" 꼴의 함의(implication)입니다. 이걸 어떻게 증명할까요? 가장 직접적인 방법은 이렇습니다.

원리 1.5.1 (함의의 직접 증명)

\( P \implies Q \)를 보이려면, "\( P \)가 참이라고 가정하자"로 시작해서, 일련의 논리적 단계를 거쳐 \( Q \)가 참이라는 결론에 이르면 됩니다.

예제 1.5.2

주장: 정수 \( n \)에 대해, \( n \)이 짝수이면 \( n^2 \)도 짝수이다.

증명. \( n \)이 짝수라고 가정하자. 그러면 어떤 정수 \( k \)에 대해 \( n = 2k \)로 쓸 수 있다. 따라서

\[ n^2 = (2k)^2 = 4k^2 = 2(2k^2). \]

\( 2k^2 \)는 정수이므로 \( n^2 \)도 \( 2 \cdot (\text{정수}) \) 꼴이다. 즉 \( n^2 \)은 짝수이다. ∎

이때 한 가지 헷갈리는 지점이 있습니다. \( P \)가 거짓일 때 \( P \implies Q \)는 무엇일까요? 수학에서는 약속에 의해 \( P \)가 거짓이면 \( P \implies Q \)는 자동으로 참이 됩니다. "전제가 무너지면 무엇이든 결론으로 삼아도 된다"라는 뜻이에요. 이걸 공허한 참(vacuously true)이라고 부릅니다.

PQP → Q
TTT
TFF
FTT
FFT

한국어 학생이 자주 헷갈리는 곳

"비가 안 왔는데 땅이 젖어 있다고 해서 '비가 오면 땅이 젖는다'가 거짓이 되지는 않잖아?" 같은 식으로 생각하면 편합니다. 함의는 "전제가 참인 상황에서 결론이 참이라고 약속한 것"일 뿐, 전제가 거짓일 때까지 보장하는 게 아니에요. 그래서 \( 0 = 1 \implies \text{나는 천재이다} \) 같은 농담식 함의도 수학적으로는 그냥 참입니다.

또 한 가지, 대우(contrapositive)역(inverse)을 구분해야 합니다. \( P \implies Q \)에 대해

  • 대우: \( \lnot Q \implies \lnot P \). 원래 명제와 같은 진릿값을 가집니다.
  • 역: \( Q \implies P \). 원래 명제와 진릿값이 다를 수 있습니다.
  • 이(inverse): \( \lnot P \implies \lnot Q \). 역과 같은 진릿값을 가집니다(즉 일반적으로 원래와 다릅니다).

예를 들어 "비가 오면 땅이 젖는다"의 대우는 "땅이 젖지 않으면 비가 오지 않았다"이고 항상 같이 참/거짓이지만, 역인 "땅이 젖었으면 비가 왔다"는 원래 명제가 참이어도 거짓일 수 있습니다(스프링클러가 있으니까요). 시험에서 가장 자주 실수하는 지점이니 꼭 기억해 둡시다.

1.6 동치 증명 Proving an "If and Only If"

명제가 \( P \iff Q \) 꼴이라면, 이는 "\( P \)와 \( Q \)는 동시에 참이거나 동시에 거짓이다"라는 뜻입니다. 이걸 증명하는 방법은 두 가지가 흔합니다.

원리 1.6.1 (양방향 증명)

\( P \iff Q \)를 보이려면, \( P \implies Q \)와 \( Q \implies P \)를 각각 증명하면 됩니다. 보통 첫 번째 방향을 "(⇒)", 두 번째 방향을 "(⇐)"로 표시해요.

예제 1.6.2

주장: 정수 \( n \)에 대해, \( n \)이 짝수일 필요충분조건은 \( n^2 \)이 짝수인 것이다.

증명.

(⇒) \( n \)이 짝수이면 \( n^2 \)도 짝수임은 예제 1.5.2에서 이미 보였습니다.

(⇐) 이번에는 대우를 사용합시다. \( n \)이 홀수라고 가정하면 \( n = 2k+1 \) 꼴이고,

\[ n^2 = (2k+1)^2 = 4k^2 + 4k + 1 = 2(2k^2 + 2k) + 1 \]

이므로 \( n^2 \)도 홀수입니다. 따라서 \( n^2 \)이 짝수이면 \( n \)도 짝수예요. ∎

두 번째 방법은 동치 사슬(chain of equivalences)을 만드는 것입니다. \( P \iff P_1 \iff P_2 \iff \cdots \iff Q \)처럼 한 단계씩 동치 변환만으로 \( P \)에서 \( Q \)까지 가는 방식이에요. 단, 모든 단계가 정말로 동치 관계여야 합니다. 한 군데서 한쪽으로만 함의되면 사슬이 깨져요.

노트

"필요충분조건"이라는 한국어 표현이 처음에는 헷갈릴 수 있어요. 보통 "\( P \)는 \( Q \)이기 위한 필요조건"은 \( Q \implies P \)이고, "충분조건"은 \( P \implies Q \)입니다. 둘 다 성립하면 동치예요. 대학 시험에서 단어 함정으로 자주 등장하니 외워 두면 좋습니다.

1.7 경우 분리 증명 Proof by Cases

때로는 명제를 한 번에 증명하기보다, 가능한 모든 상황을 몇 개의 경우로 나눠 각각에서 증명하는 게 훨씬 편합니다. 이걸 경우 분리 증명(proof by cases)이라 합니다.

원리 1.7.1 (경우 분리)

증명하려는 명제의 영역을 \( C_1, C_2, \dots, C_k \)로 빠짐없이 나누고(즉 적어도 하나의 \( C_i \)에는 반드시 속함), 각 \( C_i \)에서 결론이 성립함을 보이면 전체에서 명제가 성립합니다.

예제 1.7.2

주장: 모든 정수 \( n \)에 대해 \( n^2 + n \)은 짝수이다.

증명. 정수 \( n \)을 두 경우로 나누자.

경우 1. \( n \)이 짝수. 그러면 \( n = 2k \)이므로 \( n^2 + n = 4k^2 + 2k = 2(2k^2 + k) \), 짝수.

경우 2. \( n \)이 홀수. 그러면 \( n = 2k+1 \)이고

\[ n^2 + n = (2k+1)^2 + (2k+1) = (2k+1)\bigl((2k+1)+1\bigr) = (2k+1)(2k+2) = 2(2k+1)(k+1) \]

이므로 짝수. 두 경우 모두에서 \( n^2 + n \)이 짝수임을 보였다. ∎

경우 분리에서 가장 중요한 점은 모든 경우를 빠짐없이 다루었는가입니다. 한 경우라도 누락되면 그 영역에서 명제가 거짓일 가능성이 남아 증명이 무너지죠. 때문에 "이 외의 경우는 가능하지 않다"는 한 줄이라도 명시하는 습관이 좋습니다.

위트 한 줄

"모든 말이 같은 색이다"라는 가짜 정리에 대한 가짜 귀납 증명도 경우를 잘못 묶은 사례로 자주 인용됩니다. 거기에서는 두 마리 무리를 한 마리씩 두 번 보면서 "교집합이 비지 않으니 색이 같다"라고 하는데, 정작 \( n=2 \)일 때는 교집합이 빈집합이라는 사실을 빼먹어요. 경우 나누기는 자유지만, 빈자리가 있으면 결국 이런 코미디가 됩니다.

1.8 모순법 Proof by Contradiction

직접 증명이 막힐 때 강력하게 작동하는 무기가 모순법(proof by contradiction)입니다. 핵심 아이디어는 단순합니다. \( P \)를 보이고 싶다면, "\( P \)가 거짓이라고 가정해 보자"라고 시작해서 그 가정으로부터 명백한 모순(예: \( 0 = 1 \) 같은 것)을 끌어냅니다. 그러면 \( \lnot P \)는 받아들일 수 없고, 따라서 \( P \)가 참이어야 합니다.

원리 1.8.1 (모순법)

\( P \)를 보이려면, \( \lnot P \)를 가정한 뒤 그로부터 모순을 도출하면 됩니다.

예제 1.8.2 (\( \sqrt{2} \)는 무리수)

주장: \( \sqrt{2} \)는 유리수가 아니다.

증명(모순법). 결론을 부정해 \( \sqrt{2} \)가 유리수라고 가정하자. 그러면 서로소인 두 정수 \( a, b \)(단 \( b \neq 0 \))에 대해

\[ \sqrt{2} = \frac{a}{b} \]

로 쓸 수 있다. 양변을 제곱하면 \( 2 = \dfrac{a^2}{b^2} \), 곧 \( a^2 = 2b^2 \). 우변이 짝수이므로 \( a^2 \)도 짝수이고, 예제 1.6.2의 결과에서 \( a \)도 짝수이다. 따라서 \( a = 2c \)인 정수 \( c \)가 있다. 대입하면 \( (2c)^2 = 2b^2 \), 즉 \( 4c^2 = 2b^2 \), \( b^2 = 2c^2 \). 같은 논리로 \( b \)도 짝수이다. 그런데 \( a, b \)가 모두 짝수이면 둘 다 \( 2 \)로 나뉘므로 서로소라는 가정에 모순이다. ∎

모순법은 강력하지만 남용은 좋지 않습니다. 직접 증명이 가능한 명제를 굳이 모순법으로 쓰면, 독자가 "왜 부정에서 시작했지?" 하고 흐름을 따라가기 힘들어요. 직접 증명으로 풀리면 직접, 막히면 모순법, 정도로 생각하면 됩니다.

노트

모순법은 사실상 대우 증명의 일반화로 볼 수도 있습니다. \( P \implies Q \)를 모순법으로 보일 때 "\( P \)이면서 \( \lnot Q \)"를 가정해 모순을 얻는다고 하면, 이는 본질적으로 \( \lnot Q \implies \lnot P \)를 보이는 것과 같은 작업이에요.

1.9 좋은 증명의 실제 Good Proofs in Practice

지금까지 본 증명 기법들은 도구일 뿐이고, 실제로 좋은 증명을 쓰는 일은 그 도구를 어떤 태도로 다루느냐에 달려 있습니다. 정답이 정해진 일은 아니지만, 경험적으로 다음 원칙들이 도움이 됩니다.

  • 독자에게 친절할 것. 증명은 자기 자신을 위한 메모가 아니라 다른 사람에게 보내는 편지입니다. "왜 이 단계가 정당한가"를 독자가 따라올 수 있도록 충분히 설명합니다. 너무 친절해서 길어진 증명이, 너무 짧아서 막히는 증명보다 거의 항상 낫습니다.
  • 흐름을 보여줄 것. 증명의 첫 줄에 "이 증명은 \( n \)에 대한 귀납이다", "이 증명은 모순법으로 진행한다" 같은 이정표를 두면 독자가 길을 잃지 않습니다.
  • 정직할 것. 막힌 단계를 "쉽게 알 수 있다"라는 말로 덮으면 안 됩니다. 정말 쉬우면 한 줄을 더 적어서 보여 주고, 어려우면 어렵다고 인정하고 도움말을 줍니다.
  • 예제로 검증할 것. 증명을 끝낸 뒤 작은 예 한두 개로 결론이 진짜 맞는지 확인하는 습관을 들여 두세요. 예제는 증명을 대체하지는 못하지만, 잘못된 증명을 잡아내는 가장 쉬운 방법입니다.
  • 표기와 변수를 정리할 것. "여기서 \( n \)이 의미하는 게 정수 변수임을 명시", "이 \( k \)는 새로 잡은 정수임" 같은 사소한 한 줄이 독자의 두통을 막습니다.

마지막으로, 증명은 처음에 잘 안 써지는 게 정상이라는 점을 기억하세요. 실제 수학자들도 종이 한 면을 채우는 증명을 위해 십수 장의 낙서를 거칩니다. 머릿속에서 떠오른 아이디어를 정돈하고, 빈자리를 메우고, 다시 짧게 다듬는 과정이 곧 수학을 하는 일입니다. 이 책의 다음 챕터부터 우리는 이 도구들을 본격적으로 휘두르며 명제논리, 술어논리, 집합, 함수, 그래프, 이산확률에 이르기까지 이산수학의 풍경을 함께 걷게 될 거예요.

컴퓨터과학적 연결

증명은 단순히 수학 시험을 위한 것이 아닙니다. 알고리즘이 정말로 정답을 내는지(정확성), 정해진 시간 안에 끝나는지(종료성), 한정된 자원으로 동작하는지(자원 한계)는 모두 증명의 대상입니다. 자료구조의 정합성, 분산 시스템의 합의 프로토콜, 암호 시스템의 안전성도 마찬가지예요. 이산수학에서 익히는 증명 능력은, 결국 신뢰할 수 있는 소프트웨어를 만드는 능력의 다른 이름입니다.

PART I — 증명

2 정렬 원리 The Well Ordering Principle

자연수의 가장 평범해 보이는 성질 하나, "공집합이 아닌 자연수의 부분집합엔 반드시 가장 작은 원소가 있다"는 사실이 사실은 강력한 증명 도구가 됩니다. 이 원리를 정렬 원리(Well Ordering Principle, WOP)라고 부르고, 이번 장에서는 이걸로 \( \sqrt{2} \)가 무리수임을 보이고, 모든 자연수가 소수의 곱이라는 사실까지 증명해 봅니다. 미리 귀띔하자면, 정렬 원리는 5장에서 배울 수학적 귀납법과 사실상 동치(서로를 증명할 수 있는 관계)입니다. 같은 도구를 다른 모자를 쓰고 만나는 셈이에요.

2.1 정렬 원리 증명 Well Ordering Proofs

먼저 원리부터 정확히 적어 봅시다. 자연수 집합을 \( \mathbb{N} = \{0, 1, 2, 3, \ldots\} \)로 쓰겠습니다. (0을 자연수에 포함시키느냐 마느냐는 책마다 다르지만, 이 노트에서는 0을 포함합니다. 한국 교과서 관습과 다를 수 있으니 헷갈리면 \( \mathbb{N} \)을 "음수가 아닌 정수"라고 읽어 주세요.)

정의 2.1.1 (정렬 원리, Well Ordering Principle)

\( \mathbb{N} \)의 공집합이 아닌 모든 부분집합 \( S \subseteq \mathbb{N} \)은 최소 원소(minimum element)를 갖는다. 즉, 어떤 \( m \in S \)가 존재해서 모든 \( n \in S \)에 대해 \( m \le n \)이다.

너무 당연해 보이죠? 자연수 몇 개를 한 줌 집어 놓고 보면 그중 가장 작은 게 있을 수밖에 없잖아요. 그런데 이 "당연함"이 증명에 동원되면 의외로 강력합니다. 핵심 트릭은 이렇습니다. 어떤 명제가 모든 자연수에서 성립한다고 주장하고 싶을 때, 우리는 반례들의 집합을 잡습니다. 그 반례 집합이 비어 있지 않다고 가정하면, 정렬 원리에 의해 가장 작은 반례가 존재합니다. 그런데 그 "가장 작은 반례"의 성질을 자세히 들여다보면 보통 모순이 튀어나와요. 그러면 반례 집합은 처음부터 공집합이었다는 결론에 도달하고, 명제는 참이 됩니다.

노트 — 다이아몬드 광부의 비유

최소 반례를 잡는 전략은 마치 다이아몬드 광맥에서 "여기 진짜 다이아가 있다면, 가장 작은 다이아가 어딘가에 박혀 있을 거야"하고 캐 들어가는 것과 비슷합니다. 그런데 "가장 작은 다이아"라고 잡은 그 돌을 깨 보면 그 안에 더 작은 다이아가 들어 있어요. 그러면 우리가 "가장 작다"고 한 가정이 틀린 거고, 결국 처음부터 다이아 같은 건 없었다는 결론이 납니다. 좀 짓궂은 광부죠.

이 전략을 가장 고전적인 결과 하나로 시연해 봅시다. 그리스 수학자들이 발견했을 때 충격을 받았다는 그 사실, 바로 \( \sqrt{2} \)가 유리수가 아니라는 정리입니다.

정리 2.1.2 (\( \sqrt{2} \)의 무리수성)

\( \sqrt{2} \)는 유리수가 아니다. 즉, 어떤 자연수 \( a, b \)에 대해서도 \( \sqrt{2} = a/b \)가 성립하지 않는다.

증명 (정렬 원리 사용)

모순을 위해 \( \sqrt{2} \)가 유리수라고 가정합시다. 그러면 어떤 양의 자연수 \( a, b \)가 있어서 \( \sqrt{2} = a/b \)입니다. 이제 다음 집합을 정의합니다.

\[ C = \{\, n \in \mathbb{N} \;:\; n > 0 \text{ 이고 } n\sqrt{2} \text{가 자연수}\,\}. \]

가정에 의해 \( b\sqrt{2} = a \in \mathbb{N} \)이고 \( b > 0 \)이므로 \( b \in C \)입니다. 따라서 \( C \)는 공집합이 아닙니다. 정렬 원리에 의해 \( C \)에는 최소 원소가 존재하는데, 그것을 \( n_0 \)라 부릅시다.

이제 새로운 수 \( n_1 = n_0\sqrt{2} - n_0 = n_0(\sqrt{2} - 1) \)을 생각해 봅시다. 이 수는 두 자연수의 차 (\( n_0 \sqrt{2} \in \mathbb{N} \)이고 \( n_0 \in \mathbb{N} \)) 이므로 정수입니다. 그리고 \( 1 < \sqrt{2} < 2 \)이므로 \( 0 < \sqrt{2} - 1 < 1 \), 따라서 \( 0 < n_1 < n_0 \). 자연수네요.

그런데

\[ n_1 \sqrt{2} = n_0(\sqrt{2} - 1)\sqrt{2} = n_0(2 - \sqrt{2}) = 2n_0 - n_0\sqrt{2}. \]

\( 2n_0 \)도 자연수, \( n_0 \sqrt{2} \)도 자연수이므로 \( n_1 \sqrt{2} \)도 자연수입니다. 그러면 \( n_1 \in C \)이고 \( n_1 < n_0 \). 이는 \( n_0 \)가 \( C \)의 최소 원소라는 사실에 모순입니다. 따라서 \( \sqrt{2} \)는 유리수일 수 없습니다.

흔히 알려진 증명("\( a, b \)를 서로소로 잡으면 둘 다 짝수가 되어 모순")과는 사뭇 다른 분위기죠? 사실 두 증명은 정신은 같습니다. 둘 다 "유리수 표현이 있다면 더 단순한 표현이 또 있다"는 무한강하법(infinite descent)의 변주예요. 정렬 원리 버전은 그 무한 내려가기를 "가장 작은 반례"라는 한 번의 모순으로 깔끔하게 묶어 줍니다.

노트 — \( \mathbb{N} \) 안에서만 통한다

정렬 원리는 \( \mathbb{N} \)의 부분집합에 대해서만 보장됩니다. 정수 집합 \( \mathbb{Z} \)에는 \( \{\ldots, -3, -2, -1\} \)처럼 최소 원소가 없는 부분집합이 잔뜩 있고, 실수 \( \mathbb{R} \)에서는 열린 구간 \( (0, 1) \)이 비어 있지 않으면서도 최소 원소가 없죠. 그래서 정렬 원리를 쓰는 증명은 항상 "자연수 안에서만 비교한다"는 점을 분명히 해야 합니다.

2.2 WOP 증명 템플릿 Template for WOP Proofs

앞 절의 증명을 들여다보면, 정렬 원리를 쓰는 증명은 거의 같은 골격을 따릅니다. 이걸 한 번 정리해 두면, 비슷한 문제를 만났을 때 빈칸 채우기 게임처럼 풀 수 있어요.

WOP 증명 템플릿

"모든 자연수 \( n \)에 대해 명제 \( P(n) \)이 참이다"를 보이고 싶을 때:

1. 반례 집합 정의: \( C = \{\, n \in \mathbb{N} : P(n)\text{이 거짓}\,\} \)으로 둔다.
2. 목표 선언: \( C = \emptyset \)임을 보이는 것이 목표이다.
3. 모순을 위한 가정: \( C \neq \emptyset \)이라고 가정한다.
4. 최소 원소 호출: 정렬 원리에 의해 \( C \)에는 최소 원소 \( n_0 \)가 존재한다.
5. 모순 도출: \( n_0 \)의 성질을 분석해서, 더 작은 반례 \( n_1 \in C \)를 만들거나, \( n_0 \) 자체가 \( P(n_0) \)을 만족함을 보여 모순을 이끈다.
6. 결론: 따라서 \( C = \emptyset \), 즉 모든 \( n \)에 대해 \( P(n) \)이 참이다.

여기서 가장 까다로운 단계는 5번이에요. "더 작은 반례를 어떻게 만드느냐"는 명제마다 다르고, 그게 사실상 증명의 본체입니다. \( \sqrt{2} \) 증명에서는 \( n_1 = n_0(\sqrt{2} - 1) \)이라는 영리한 한 수를 둬서 \( n_1 \)이 \( n_0 \)보다 작은데도 여전히 \( C \)에 속하게 만들었죠.

한 가지만 더. 모순을 이끄는 방법은 두 가지 결이 있습니다.

  • "하강(descent)" 모순: 위처럼 \( n_0 \)보다 작은 반례 \( n_1 \)을 명시적으로 구성해서 "최소"라는 성질에 직접 모순을 줌.
  • "부정(refutation)" 모순: \( n_0 \)가 사실은 \( P(n_0) \)을 만족함을 보여서 \( n_0 \in C \)에 모순을 줌. 이 경우 \( n_0 \)가 \( C \)의 최소 원소라는 사실 자체보다도 \( n_0 \in C \)라는 더 약한 정보를 모순의 재료로 씀.

실전에서는 둘 중 어느 쪽이든 자연스러운 쪽으로 가면 됩니다. 다음 절에서 보여줄 소인수분해 증명은 하강의 변형으로 풀어 보겠습니다.

예제 2.2.1 — 작은 워밍업

"모든 자연수 \( n \)에 대해 \( n^2 \ge n \)이다"를 정렬 원리로 보여 봅시다. 반례 집합 \( C = \{n \in \mathbb{N} : n^2 < n\} \). 가정상 \( C \neq \emptyset \)이면 최소 원소 \( n_0 \)가 있고, \( n_0^2 < n_0 \)입니다. \( n_0 = 0 \)이면 \( 0 < 0 \)이라는 모순. \( n_0 \ge 1 \)이면 양변을 \( n_0 \)로 나눠 \( n_0 < 1 \), 즉 \( n_0 = 0 \)이라는 모순. 어느 쪽이든 막힙니다. 따라서 \( C = \emptyset \). 이 정도는 그냥 \( n(n-1) \ge 0 \)으로도 풀리지만, 템플릿에 익숙해지는 연습으로는 좋습니다.

2.3 소인수분해 Factoring into Primes

이번엔 좀 더 묵직한 결과로 가 봅시다. 학교에서부터 익숙한 사실 — "모든 1보다 큰 자연수는 소수들의 곱으로 쓸 수 있다" — 을 정렬 원리로 정확하게 증명해 보겠습니다. 정확한 진술은 이렇습니다.

정의 2.3.1 (소수)

\( p \in \mathbb{N} \)이 소수(prime)라는 것은, \( p \ge 2 \)이면서 \( p \)의 양의 약수가 \( 1 \)과 \( p \)뿐인 경우를 말한다. 그렇지 않은 \( n \ge 2 \)는 합성수(composite)라고 한다.

정리 2.3.2 (소인수분해의 존재성)

모든 자연수 \( n \ge 2 \)에 대해, \( n \)을 소수들의 곱으로 표현할 수 있다. 즉, 어떤 소수들 \( p_1, p_2, \ldots, p_k \) (반드시 서로 다를 필요는 없음)가 존재해서 \( n = p_1 p_2 \cdots p_k \)이다. (한 개짜리 곱, 즉 \( n \)이 그 자체로 소수인 경우 \( k = 1 \)도 허용한다.)

증명 (정렬 원리)

반례 집합을 다음처럼 잡습니다.

\[ C = \{\, n \in \mathbb{N} : n \ge 2 \text{ 이고 } n\text{을 소수의 곱으로 쓸 수 없다}\,\}. \]

주장은 \( C = \emptyset \)입니다. 모순을 위해 \( C \neq \emptyset \)이라 가정하고, 정렬 원리에 의해 최소 원소 \( n_0 \in C \)를 잡습니다.

\( n_0 \)는 두 가지 가능성을 가집니다.

경우 1: \( n_0 \)가 소수. 그러면 \( n_0 = n_0 \) 자체가 소수 한 개의 곱이고, 이는 정의 2.3.1에 따라 정리 2.3.2의 표현에 해당합니다. 즉 \( n_0 \notin C \). 가정에 모순.

경우 2: \( n_0 \)가 합성수. 그러면 \( n_0 = a \cdot b \)인 자연수 \( a, b \)가 존재하고, \( 1 < a, b < n_0 \)입니다. 두 인수 모두 \( 2 \) 이상이고 \( n_0 \) 미만이죠. 그런데 \( n_0 \)는 \( C \)의 최소 원소입니다. 즉 \( a, b < n_0 \)인 \( 2 \) 이상의 자연수는 모두 \( C \)에 속하지 않습니다. 그러므로 \( a, b \) 각각은 소수의 곱으로 표현됩니다.

\[ a = p_1 p_2 \cdots p_r, \qquad b = q_1 q_2 \cdots q_s. \]

그렇다면 두 표현을 그대로 이어 붙이면

\[ n_0 = a \cdot b = p_1 p_2 \cdots p_r \, q_1 q_2 \cdots q_s, \]

역시 소수들의 곱입니다. 그러면 \( n_0 \notin C \). 가정에 모순.

두 경우 모두 모순이므로 처음의 \( C \neq \emptyset \) 가정이 틀렸고, \( C = \emptyset \)입니다. 따라서 \( 2 \) 이상의 모든 자연수는 소수들의 곱으로 표현됩니다.

노트 — "유일성"은 또 다른 이야기

이 정리는 소인수분해의 존재성만 보장합니다. \( 12 = 2 \cdot 2 \cdot 3 \) 같은 표현이 본질적으로 유일하다는 사실(산술의 기본 정리, fundamental theorem of arithmetic)은 별도의 증명이 필요해요. 그건 보통 약수 보조정리(\( p \mid ab \implies p \mid a \) 또는 \( p \mid b \))를 거쳐 증명하고, 이 노트의 뒤쪽 정수론 장에서 다룰 예정입니다. 즉 지금은 "소수 부품으로 분해할 수 있다"까지만 안전하게 챙겨 두는 거예요.

잠깐 컴퓨터과학 사이드로 빠지자면, 이 증명은 사실상 재귀적 분해 알고리즘의 정당성을 그대로 보여줍니다. 어떤 \( n \)이 들어왔을 때 (1) 소수면 그대로 반환, (2) 합성수면 \( n = ab \)인 \( a, b \)를 찾아 각각 재귀적으로 분해, 처럼 짠 함수가 항상 종료한다는 것 — 이게 정렬 원리가 보장해 주는 것이에요. 매번 더 작은 자연수에서 호출되니까, 무한히 내려갈 수가 없는 거죠. 5장의 강한 귀납법(strong induction)도 같은 사실을 다른 각도에서 말합니다.

예제 2.3.3 — 손으로 한 번

\( 84 \)를 분해해 봅시다. \( 84 = 2 \cdot 42 \). \( 42 = 2 \cdot 21 \). \( 21 = 3 \cdot 7 \). 이어 붙이면 \( 84 = 2 \cdot 2 \cdot 3 \cdot 7 \). 위 증명의 "두 인수 각각을 재귀적으로 분해해서 이어 붙인다"가 그대로 작동하는 모습입니다.

2.4 정렬집합 Well Ordered Sets

정렬 원리는 \( \mathbb{N} \)의 특별한 성질이지만, 같은 아이디어를 다른 순서집합에도 일반화할 수 있습니다. 일반화된 개념의 이름은 정렬집합(well ordered set)이에요.

정의 2.4.1 (정렬집합)

전순서(total order) \( \le \)가 부여된 집합 \( (S, \le) \)이 정렬집합이라는 것은, \( S \)의 공집합이 아닌 모든 부분집합에 \( \le \) 기준 최소 원소가 존재한다는 의미이다.

"전순서"라는 단서는, 임의의 두 원소 \( x, y \in S \)에 대해 항상 \( x \le y \)이거나 \( y \le x \)가 성립한다는 뜻입니다. (둘 다 성립하면 \( x = y \).) 이게 보장돼야 "최소"라는 말이 의미를 가지죠.

몇 가지 예를 봅시다.

예제 2.4.2 — 정렬집합 / 정렬 아닌 집합

(a) \( \mathbb{N} \) with \( \le \): 정렬집합이다. 이게 정렬 원리.

(b) \( \mathbb{Z} \) with \( \le \): 정렬집합이 아니다. 예컨대 \( S = \{n \in \mathbb{Z} : n < 0\} \)은 비어 있지 않으면서도 최소 원소가 없다. (\( -1, -2, -3, \ldots \)이 끝없이 작아진다.)

(c) \( \mathbb{R} \) with \( \le \): 정렬집합이 아니다. 열린 구간 \( (0, 1) \)에는 최소 원소가 없다. 어떤 후보를 잡아도 그것의 절반이 더 작으니까.

(d) 음수 아닌 유리수 \( \mathbb{Q}_{\ge 0} \) with \( \le \): 정렬집합이 아니다. \( \{1/n : n \ge 1\} \)에 최소 원소가 없다(0보다 큰 어떤 \( 1/n \)을 잡아도 \( 1/(n+1) \)이 더 작다). 게다가 \( \{q \in \mathbb{Q} : q > 0\} \) 자체에도 "양의 가장 작은 유리수"는 존재하지 않는다.

노트 — 표준 순서가 아닌 다른 순서를 주면?

흥미롭게도 어떤 집합은 평소의 순서로는 정렬집합이 아니지만, 순서를 다시 줘서 정렬집합으로 만들 수 있습니다. 예를 들어 양의 유리수 \( \mathbb{Q}_{> 0} \)을 "기약분수 \( a/b \)에서 \( a + b \) 작은 순, 같으면 \( a \) 작은 순"처럼 사전식 비슷한 순서로 다시 정렬하면, 그 순서로는 모든 부분집합이 최소 원소를 갖게 만들 수 있어요. 그러나 이런 인위적 재정렬이 통하는 것은 어디까지나 가산집합(셀 수 있는 집합)에서이고, 일반적으로 임의의 집합을 정렬할 수 있다는 주장(정렬 정리, well-ordering theorem)은 선택공리(Axiom of Choice)와 동치인 강한 명제입니다. 이 노트의 범위를 좀 벗어나니 호기심으로만 남겨 두세요.

일반화의 한 좋은 예로 사전식 순서(lexicographic order)를 봅시다. 두 자연수 쌍 \( (a, b), (c, d) \in \mathbb{N} \times \mathbb{N} \)에 대해

\[ (a, b) \le_{\text{lex}} (c, d) \iff a < c \;\;\text{또는}\;\; (a = c \text{ 이고 } b \le d). \]

로 정의합시다. 사전에서 단어를 정렬하는 방식과 정확히 같죠. 이 순서로 \( \mathbb{N}^2 \)는 정렬집합이 됩니다.

정리 2.4.3

\( (\mathbb{N} \times \mathbb{N}, \le_{\text{lex}}) \)은 정렬집합이다.

증명 스케치

\( T \subseteq \mathbb{N} \times \mathbb{N} \)이 비어 있지 않다고 하자. \( T \)에 등장하는 첫째 좌표들의 집합 \( A = \{ a : \exists b,\, (a, b) \in T \} \subseteq \mathbb{N} \)을 보면, \( A \)는 비어 있지 않으므로 정렬 원리에 의해 최소 원소 \( a_0 \)가 있다. 이제 \( B = \{ b : (a_0, b) \in T \} \)을 보면 이것도 비어 있지 않은 \( \mathbb{N} \)의 부분집합이고, 따라서 최소 원소 \( b_0 \)를 갖는다. 그러면 \( (a_0, b_0) \in T \)이고 \( \le_{\text{lex}} \) 정의상 이는 \( T \)의 최소 원소이다.

이 결과는 단순히 추상적 호기심이 아닙니다. 알고리즘에서 종료성을 증명할 때 단일 자연수 카운터로는 안 되는 경우, "사전식 순으로 줄어드는 (a, b) 쌍"을 잡아 종료를 보이는 기법이 자주 등장합니다. 예를 들어 두 카운터 중 하나가 가끔 늘어나도, 사전식 순서로는 전체가 줄어든다면 알고리즘은 반드시 종료하죠. 이 사실의 정당화가 정확히 정리 2.4.3이에요.

노트 — 정렬 원리와 귀납법의 동치성, 살짝 맛보기

장 도입에서 예고한 대로, 정렬 원리는 수학적 귀납법(특히 강한 귀납법)과 동치입니다. 직관은 이렇습니다. 만약 \( P(0) \)이 참이고 "\( k < n \)에서 \( P \)가 참이면 \( P(n) \)도 참"이라는 점화 단계가 성립한다면, 반례 집합 \( C = \{n : \neg P(n)\} \)에 최소 원소가 있다고 해 봐야 그 최소 원소 자체가 점화 단계에 의해 \( P \)를 만족하게 되어 모순. 즉 강한 귀납법은 정렬 원리로 환원됩니다. 반대 방향도 가능합니다. 자세한 형식 증명은 5장에서 다시 만나요. 지금은 "두 도구가 같은 도구의 두 얼굴"이라는 그림만 머리에 남겨 두면 충분합니다.

예제 2.4.4 — 종료성 한 컷

두 자연수 \( m, n \)에 대해 다음 절차를 생각해 보자. (1) \( m = 0 \)이면 멈춤. (2) \( n > 0 \)이면 \( n \)을 \( 1 \) 줄이고 다시 (1)로. (3) \( n = 0 \)이면 \( m \)을 \( 1 \) 줄이고 \( n \)을 임의의 자연수로 재설정한 뒤 다시 (1)로. 단계 (3) 때문에 \( n \)은 마구 커질 수 있어 단순 카운터로는 종료를 못 보이지만, 매 단계마다 쌍 \( (m, n) \)이 \( \le_{\text{lex}} \) 기준으로 엄격히 줄어든다. \( \mathbb{N} \times \mathbb{N} \)이 정렬집합이므로 무한 하강 수열은 존재할 수 없고, 따라서 절차는 반드시 종료한다.

여기까지가 정렬 원리의 첫 만남입니다. 핵심을 다시 한 줄로 추리면 이렇습니다. "가장 작은 반례"는 종종 자기 자신을 부정한다 — 그러므로 처음부터 반례는 없었다. 이 한 문장이 \( \sqrt{2} \)의 무리수성에서부터 소인수분해 존재성, 알고리즘 종료성에 이르기까지 폭넓게 작동합니다. 다음 장부터는 같은 정신을 또 다른 모습으로 — 명제논리의 추론 규칙들로, 그리고 5장에서는 귀납법의 옷으로 — 다시 만나게 될 거예요.

PART I — 증명

3 논리식 Logical Formulas

컴퓨터 프로그램의 if 문 하나를 들여다보면 그 안에는 작은 명제 하나가 들어 있습니다. "x가 양수이고 y가 0이 아니면..."처럼요. 이 챕터에서는 그런 명제를 다듬고 조립하는 도구인 명제논리술어논리를 배웁니다. 진리표로 시작해서, 동치 변형, 정규형, SAT 문제, 양화사까지 — 코드를 추론할 때, 회로를 설계할 때, 그리고 앞으로 이 책 전체에서 증명을 쓸 때 쓸 도구들을 모두 챙겨갑니다.

3.1 명제로 명제 만들기 Propositions from Propositions

2장에서 우리는 "명제"를 참 또는 거짓 둘 중 하나로 판정되는 진술이라고 약속했습니다. 그런데 실제로 우리가 쓰는 진술들은 보통 작은 명제 여러 개를 이어 붙인 모양을 하고 있습니다. "오늘 비가 오면 우산을 챙긴다"처럼 말이죠. 이렇게 작은 명제로 큰 명제를 만드는 도구가 논리 연산자입니다.

정의 3.1.1 (기본 논리 연산자)

명제 \(P, Q\)가 주어졌을 때 다음 다섯 가지 연산을 사용합니다.

· 부정 \(\lnot P\): "\(P\)가 아니다" — \(P\)의 진릿값을 뒤집습니다.
· 논리곱 \(P \land Q\): "\(P\) 그리고 \(Q\)" — 둘 다 참일 때만 참.
· 논리합 \(P \lor Q\): "\(P\) 또는 \(Q\)" — 적어도 하나가 참이면 참 (포함적 OR).
· 함의 \(P \to Q\): "\(P\)이면 \(Q\)" — \(P\)가 참인데 \(Q\)가 거짓일 때만 거짓.
· 쌍조건 \(P \leftrightarrow Q\): "\(P\)와 \(Q\)는 동치" — 진릿값이 같을 때만 참.

이걸 한눈에 정리한 게 그 유명한 진리표입니다. T는 참(true), F는 거짓(false)입니다.

\(P\)\(Q\)\(\lnot P\)\(P \land Q\)\(P \lor Q\)\(P \to Q\)\(P \leftrightarrow Q\)
TTFTTTT
TFFFTFF
FTTFTTF
FFTFFTT

노트 — 함의의 함정

한국어 학생이 가장 헷갈려 하는 칸은 \(P \to Q\)에서 \(P\)가 거짓일 때입니다. "비가 오면 우산을 챙긴다"라는 약속을 했는데 오늘 비가 안 왔다면, 우산을 챙겼든 안 챙겼든 약속은 어겨지지 않았습니다. 그래서 \(P\)가 거짓이면 \(P \to Q\)는 무조건 참 — 이를 공허하게 참(vacuously true)이라고 부릅니다. "내가 만약 1조 원이 있다면 너한테 100억을 주겠다"는 진심으로 참인 약속이에요. 1조 원이 없으니까요.

또 자주 등장하는 친구가 배타적 논리합(XOR), 기호로는 \(P \oplus Q\)입니다. "둘 중 정확히 하나만 참"일 때 참이 됩니다. 일상에서 "커피 아니면 차"라고 말할 때 보통 둘 다 마시겠다는 뜻이 아니죠 — 그게 XOR입니다.

\(P\)\(Q\)\(P \oplus Q\)
TTF
TFT
FTT
FFF

예제 3.1.2

"세 자리 수 \(n\)이 짝수이고 9의 배수이다"라는 진술을 \(P\)는 "\(n\)이 짝수", \(Q\)는 "\(n\)이 9의 배수"로 두면 \(P \land Q\). 한편 "\(n\)이 짝수이거나 또는 9의 배수이다(또는 둘 다)"는 \(P \lor Q\)입니다. 만약 누가 "짝수거나 9의 배수, 단 둘 다는 아님"을 의미했다면 \(P \oplus Q\)가 되겠죠.

3.2 컴퓨터 프로그램 속 명제논리 Propositional Logic in Computer Programs

프로그램이 분기하는 곳마다 명제가 숨어 있습니다. if (x > 0 && y != 0) 한 줄을 보면 \(P = (x > 0)\), \(Q = (y \neq 0)\)인 \(P \land Q\)예요. while 루프의 종료 조건도 마찬가지고요. 그래서 코드를 검증하거나 리팩터링할 때 우리는 알게 모르게 명제논리 변형을 하고 있습니다.

예제 3.2.1 (단락 평가)

대부분의 언어에서 P && Q단락 평가(short-circuit)를 합니다. \(P\)가 거짓이면 \(Q\)는 평가하지 않아요. 이래서 다음 코드가 안전합니다.

if x != 0 and 100 / x > 5:
    do_something()

만약 단락 평가가 없다면 \(x = 0\)일 때 0으로 나누기가 터질 겁니다. 논리적으로는 \(P \land Q\)와 "\(P\)가 참이면 \(Q\)" 둘 다 같지만, 실행 비용은 다르다는 게 포인트예요.

또 한 가지, 회로 설계의 세계는 명제논리가 그대로 하드웨어가 되는 곳입니다. 트랜지스터로 AND, OR, NOT 게이트를 만들고, 그것들을 모아 가산기·메모리·CPU를 짭니다. 회로 한 칸의 출력은 입력에 대한 어떤 부울 함수이고, 그 함수의 명세가 곧 우리가 이번 챕터 내내 다루는 논리식입니다.

예제 3.2.2 (다수결 회로)

입력 세 비트 \(A, B, C\) 중 1이 두 개 이상이면 1, 아니면 0을 출력하는 회로의 명세는 \[ M(A,B,C) = (A \land B) \lor (B \land C) \lor (A \land C). \] 이 식은 곧 회로의 배선이 됩니다. 식의 모양을 다듬을 수 있다면 게이트 수를 줄일 수도 있겠죠 — 그래서 다음 절들의 "동치 변형"이 실제로 돈이 되는 일이 됩니다.

노트

버그 추적을 하다 보면 "이 if 조건이 정말 의도한 명제인가?"를 묻게 됩니다. 그때 우리는 머릿속으로 진리표를 그리고 있는 거예요. 명제논리는 추상적인 공부가 아니라, 매일 쓰는 디버깅 언어입니다.

3.3 동치와 타당성 Equivalence and Validity

같은 의미를 다르게 쓴 두 식이 있다면 — 진리표를 만들어서 모든 행이 같은지 보면 됩니다. 그게 핵심입니다.

정의 3.3.1 (항진명제·모순명제·동치)

· 모든 변수 배정에서 참이 되는 식을 항진명제(tautology)라고 부릅니다. 예: \(P \lor \lnot P\).
· 모든 배정에서 거짓이면 모순명제(contradiction). 예: \(P \land \lnot P\).
· 어떤 배정에서는 참, 어떤 배정에서는 거짓이면 충족가능(satisfiable)이라고 합니다.
· 두 식 \(\varphi, \psi\)가 모든 배정에서 같은 진릿값을 갖는다면 논리적 동치이며 \(\varphi \equiv \psi\)로 씁니다. 이는 \(\varphi \leftrightarrow \psi\)가 항진명제라는 말과 같습니다.

예제 3.3.2 (대우)

\(P \to Q\)와 \(\lnot Q \to \lnot P\)는 동치입니다. 진리표로 확인:

\(P\)\(Q\)\(P \to Q\)\(\lnot Q \to \lnot P\)
TTTT
TFFF
FTTT
FFTT

네 줄이 정확히 일치하니 \(P \to Q \equiv \lnot Q \to \lnot P\). 이게 우리가 자주 쓰는 대우(contrapositive)의 정당화이고, 이미 2장에서 본 "대우에 의한 증명"이 왜 합법인지의 근거입니다.

노트 — 함의와 그 친척들

\(P \to Q\)에 대해 다음을 구분합니다.
· 역(converse): \(Q \to P\). 일반적으로 동치 아님.
· 이(inverse): \(\lnot P \to \lnot Q\). 일반적으로 동치 아님.
· 대우(contrapositive): \(\lnot Q \to \lnot P\). 동치 맞음.
"비가 오면 땅이 젖는다"의 역인 "땅이 젖었으면 비가 왔다"는 거짓일 수 있다는 걸 떠올리면 됩니다 — 누가 물을 뿌렸을 수도 있죠.

또 하나 중요한 개념이 타당성(validity)입니다. 어떤 식이 항진명제이면 — 즉 어떤 진릿값을 넣어도 참이라면 — 우리는 그 식을 타당하다고 말하고, 증명에 그대로 쓸 수 있습니다. \(P \land (P \to Q) \to Q\) (이름하여 modus ponens), \(((P \to Q) \land (Q \to R)) \to (P \to R)\) (가정 삼단논법) 같은 게 그렇습니다. 추론 규칙은 결국 항진명제의 모음집이에요.

3.4 명제의 대수 The Algebra of Propositions

진리표를 매번 그리는 건 변수가 \(n\)개면 \(2^n\)줄이라 금방 폭발합니다. 그래서 우리는 동치를 대수 법칙처럼 쓰는 법을 익혀야 해요. 곱셈 분배법칙처럼, 논리식도 한 모양에서 다른 모양으로 변형할 수 있습니다.

정리 3.4.1 (기본 동치 법칙)

임의의 명제 \(P, Q, R\)에 대해 다음이 성립합니다.

· 이중부정: \(\lnot \lnot P \equiv P\).
· 교환: \(P \land Q \equiv Q \land P\), \(P \lor Q \equiv Q \lor P\).
· 결합: \((P \land Q) \land R \equiv P \land (Q \land R)\), \(\lor\)도 마찬가지.
· 분배: \(P \land (Q \lor R) \equiv (P \land Q) \lor (P \land R)\), 그리고 \(\land, \lor\) 자리를 바꾼 쌍대도.
· 흡수: \(P \land (P \lor Q) \equiv P\), \(P \lor (P \land Q) \equiv P\).
· 드모르간: \(\lnot(P \land Q) \equiv \lnot P \lor \lnot Q\), \(\lnot(P \lor Q) \equiv \lnot P \land \lnot Q\).
· 함의 풀기: \(P \to Q \equiv \lnot P \lor Q\).

증명 (드모르간 한 쪽만)

\(\lnot(P \land Q)\)는 "둘 다 참은 아니다"이고, 이는 곧 "적어도 하나는 거짓이다", 즉 \(\lnot P \lor \lnot Q\)와 같습니다. 진리표 네 줄을 다 채워봐도 두 식의 칸이 동일하게 채워집니다.

예제 3.4.2 (조건문 정리하기)

\(\lnot(P \to Q)\)를 풀어 봅시다. 함의 풀기로 \(\lnot(\lnot P \lor Q)\), 드모르간으로 \(\lnot \lnot P \land \lnot Q\), 이중부정으로 \(P \land \lnot Q\). 그러니까 "\(P\)이면 \(Q\)"의 부정은 "\(P\)인데 \(Q\)가 아니다"입니다 — 약속을 정확히 어기는 단 한 가지 방식이죠.

이런 변형을 충분히 하면 어떤 명제든 정해진 모양으로 맞출 수 있습니다. 두 가지 표준형이 특히 자주 등장합니다.

정의 3.4.3 (CNF와 DNF)

· 리터럴(literal): 변수 또는 변수의 부정. 예: \(P\), \(\lnot Q\).
· 절(clause): 리터럴들을 \(\lor\)로 묶은 것.
· 합접 정규형(CNF, Conjunctive Normal Form): 절들의 \(\land\) 묶음. 형태: \[ (\ell_{11} \lor \ell_{12} \lor \cdots) \land (\ell_{21} \lor \cdots) \land \cdots \]
· 이접 정규형(DNF, Disjunctive Normal Form): \(\land\) 묶음들의 \(\lor\) 묶음. CNF의 쌍대.

정리 3.4.4

모든 명제식은 동치인 CNF, 그리고 동치인 DNF로 변환할 수 있습니다.

증명 스케치

주어진 식의 진리표를 만든 뒤, DNF는 "참이 되는 행마다 그 행을 뽑아내는 \(\land\) 항을 만들어 \(\lor\)로 합치"면 끝. CNF는 거짓이 되는 행마다 그 행을 막는 절을 만들어 \(\land\)로 묶으면 됩니다. 그러므로 어느 식이든 두 정규형이 모두 존재합니다.

예제 3.4.5

\(P \to Q\)를 CNF로: 함의 풀기로 \(\lnot P \lor Q\) — 이미 한 절짜리 CNF예요. DNF로는? 진리표에서 참이 되는 행은 (T,T), (F,T), (F,F)니까 \[ (P \land Q) \lor (\lnot P \land Q) \lor (\lnot P \land \lnot Q). \] 흡수와 분배로 더 줄일 수 있지만 일단 정의대로면 이 모양입니다.

3.5 SAT 문제 The SAT Problem

변수 \(n\)개짜리 식이 충족가능한지 — 즉 어떤 진릿값 배정에서 참이 되는지 — 를 물어보는 문제가 SAT입니다. 이름부터가 "satisfiability". 단순해 보이지만, 컴퓨터과학에서 가장 유명한 어려운 문제 중 하나예요.

정의 3.5.1 (SAT)

입력으로 명제식 \(\varphi\)가 주어졌을 때, \(\varphi\)를 참으로 만드는 변수 배정이 존재하는지를 결정하는 문제. CNF로 입력이 주어진 경우는 CNF-SAT, 절마다 리터럴이 정확히 \(k\)개이면 \(k\)-SAT이라 부릅니다.

변수가 \(n\)개면 가능한 배정은 \(2^n\)가지. 가장 단순한 알고리즘은 모두 시도해 보는 것이고, \(n=60\)만 되어도 \(10^{18}\) 근처라 현실적이지 않습니다. 이걸 다항시간에 푸는 알고리즘이 있느냐? — 그게 그 유명한 \(\mathsf{P}\) vs \(\mathsf{NP}\) 문제입니다.

정리 3.5.2 (Cook–Levin, 1971)

SAT은 NP-완전(NP-complete)입니다. 즉 NP에 속하는 모든 문제가 SAT으로 다항시간 환원됩니다. SAT을 빠르게 푸는 알고리즘이 있다면, NP의 모든 문제가 빠르게 풀립니다.

노트 — 그런데 실용 SAT solver는 잘 돕니다

이론상 어려운 문제이지만, 산업용 SAT solver(MiniSat, Glucose, CaDiCaL 등)는 변수 수백만 개짜리 실제 문제를 몇 초만에 풉니다. 이유는 (1) 진짜 무작위 입력이 아니라 구조가 있는 입력이고, (2) DPLL/CDCL 같은 백트래킹+학습 알고리즘이 똑똑하게 가지치기하기 때문입니다. 그래서 SAT은 칩 검증, 소프트웨어 모델 체킹, 스케줄링, 심지어 일부 보안 분석에까지 실전 도구로 쓰입니다.

예제 3.5.3 (간단한 SAT 인스턴스)

\(\varphi = (P \lor Q) \land (\lnot P \lor R) \land (\lnot Q \lor \lnot R)\). 충족 가능한가? \(P=\)T, \(Q=\)F, \(R=\)T로 두면 첫 절 T, 둘째 절 T, 셋째 절 \(\lnot Q \lor \lnot R = \)T\(\lor \)F\(=\)T. 그래서 충족 가능. 변수 셋이라 \(2^3=8\)개의 배정만 시험하면 되지만, 변수가 1만 개라면 얘기가 달라집니다.

3.4절의 정규형 변환과 합치면 그림이 또렷해집니다. 임의의 명제를 CNF로 옮길 수 있으므로 "충족가능성을 묻는 문제"의 정규 형태는 CNF-SAT이고, 거의 모든 SAT solver는 CNF 입력을 받습니다. 이 작은 사실 — 모든 부울 추론을 CNF 한 통에 욱여넣을 수 있다는 사실 — 이 컴퓨터로 논리를 다루는 일을 가능하게 만든 결정적 한 수예요.

3.6 술어식 Predicate Formulas

명제논리는 "참/거짓이 정해진 진술"만 다뤘습니다. 그런데 수학에서 우리는 자주 "\(x > 0\)"이나 "\(x\)는 소수다" 같이 변수에 따라 참/거짓이 갈리는 진술을 씁니다. 이런 걸 술어(predicate)라고 해요.

정의 3.6.1 (술어와 양화사)

변수를 매개변수로 받아 명제를 돌려주는 것을 술어라고 합니다. 예: \(P(x): \) "\(x\)는 짝수다", \(L(x,y): \) "\(x\)는 \(y\)보다 작다".

여기에 두 가지 양화사(quantifier)를 붙여 진릿값이 정해진 명제를 만듭니다. 논의역(domain)을 \(D\)라고 할 때:

· 전칭 \(\forall x \in D.\, P(x)\): "모든 \(x\)에 대해 \(P(x)\)가 참".
· 존재 \(\exists x \in D.\, P(x)\): "어떤 \(x\)가 있어 \(P(x)\)가 참".

예제 3.6.2

논의역을 자연수 \(\mathbb{N}\)으로 두면 \(\forall n.\, n^2 \ge 0\)은 참, \(\exists n.\, n^2 = 2\)는 거짓(자연수에는 \(\sqrt 2\)가 없으니까), \(\exists n.\, n > 100\)은 참입니다. 논의역이 바뀌면 같은 식의 진릿값도 바뀐다는 점에 유의하세요.

양화사 식의 부정은 자주 쓰니 외워둘 가치가 있습니다.

정리 3.6.3 (양화사 부정 — 일반화 드모르간)

\[ \lnot \forall x.\, P(x) \equiv \exists x.\, \lnot P(x), \qquad \lnot \exists x.\, P(x) \equiv \forall x.\, \lnot P(x). \]

노트

"모두가 행복하다의 부정"은 "아무도 행복하지 않다"가 아니라 "행복하지 않은 사람이 적어도 한 명 있다"입니다. 일상의 직관과 정확히 맞아떨어지는 규칙이에요.

이제 진짜 흥미로운 부분으로. 양화사가 두 개 이상 붙으면 순서가 의미를 결정합니다.

정의 3.6.4 (양화사 순서)

논의역 \(D\)에서 술어 \(R(x,y)\)에 대해 \[ \forall x.\, \exists y.\, R(x,y) \quad \text{vs.} \quad \exists y.\, \forall x.\, R(x,y). \] 앞엣것은 "각 \(x\)마다 \(y\)를 따로 고를 수 있다"를, 뒤엣것은 "모든 \(x\)에게 통하는 단 하나의 \(y\)가 있다"를 뜻합니다.

예제 3.6.5 (정수에서)

\(R(x,y): y > x\). 논의역은 \(\mathbb{Z}\).
· \(\forall x.\, \exists y.\, y > x\): 임의의 \(x\)에 대해 \(y = x+1\)로 두면 됨. .
· \(\exists y.\, \forall x.\, y > x\): 모든 정수보다 큰 정수가 있어야 함 — 그런 건 없으므로 거짓.
식의 변수 두 개를 그대로 두고 양화사 순서만 바꿨는데 진릿값이 정반대가 됐습니다.

노트 — 연애 비유

학생들이 자주 드는 익살스러운 예. \(L(x,y): x\text{는 }y\text{를 사랑한다}\), 논의역은 사람 전체.
· \(\forall x.\, \exists y.\, L(x,y)\): "모두에게 사랑하는 누군가가 있다." 사람마다 자기 짝이 따로 있어도 됩니다.
· \(\exists y.\, \forall x.\, L(x,y)\): "모두가 사랑하는 단 한 사람이 있다." 이건 슈퍼스타급 인물이 필요한 훨씬 센 주장이에요.
두 번째가 첫 번째를 함의합니다 (\(\exists \forall \to \forall \exists\)). 그러나 그 역은 일반적으로 거짓 — 우리 일상이 정확히 그렇죠.

예제 3.6.6 (해석학에서 자주 보는 것)

함수 \(f\)의 연속성과 균등 연속성의 차이도 양화사 순서로 갈립니다. 직관적으로:
· 연속: \(\forall x.\, \forall \varepsilon > 0.\, \exists \delta > 0.\, \cdots\) — \(\delta\)가 \(x\)에 따라 달라도 됨.
· 균등 연속: \(\forall \varepsilon > 0.\, \exists \delta > 0.\, \forall x.\, \cdots\) — 한 \(\delta\)가 모든 \(x\)에 통해야 함.
"\(\forall \exists\)"가 "\(\exists \forall\)"가 되는 순간 조건이 훨씬 강해집니다.

술어식까지 갖추면 우리는 이 책 뒷부분에서 만날 거의 모든 수학적 진술을 정밀하게 적을 수 있습니다. "모든 자연수 \(n\)에 대해 어떤 소수 \(p\)가 있어 \(p > n\)이다"라는 진술은 그대로 \(\forall n \in \mathbb{N}.\, \exists p \in \mathrm{Prime}.\, p > n\)이고, 이걸 증명하면 소수가 무한히 많다는 정리가 됩니다 (유클리드, 곧 4장에서).

정리하며

이번 챕터에서 우리는 명제논리의 다섯 연산자, 진리표로 동치 검증, 드모르간·분배·흡수 같은 변형 법칙, 정규형(CNF/DNF), 그리고 양화사까지 챙겼습니다. 이 도구들은 이 책의 나머지 모든 챕터에서 — 귀납 증명에서, 그래프 정리에서, 알고리즘 분석에서 — 같이 다닙니다. if 문을 다시 볼 때마다 "여긴 \(P \land Q\)였지" 하고 한번 떠올려 보세요. 그 작은 습관이 이산수학을 익히는 가장 빠른 길입니다.

PART I — 증명

4 수학적 데이터 타입 Mathematical Data Types

증명을 한참 다뤘으니 이제 잠깐 다른 이야기를 해볼까 합니다. 수학자에게도 자료구조가 필요합니다. 프로그래머가 배열, 리스트, 해시맵 없이 코드를 짤 수 없듯, 수학자도 무언가를 담아두고 꺼내고 묶을 그릇이 있어야 합니다. 이 챕터에서는 수학의 가장 기본적인 자료구조 셋, 즉 집합, 수열, 함수를 차례로 만나고, 거기에 이항관계유한 기수까지 얹어보겠습니다. 컴퓨터과학에서 배운 set, list, map의 뿌리가 모두 여기에 있습니다.

4.1 집합 Sets

가장 단순한 그릇부터 시작합시다. 집합(set)은 그저 "물건들의 모임"입니다. 그런데 보통의 모임과 다른 점이 두 가지 있어요. 첫째, 순서가 없습니다. 둘째, 중복이 없습니다. 그래서 \(\{1, 2, 3\}\)과 \(\{3, 1, 2\}\), 그리고 \(\{1, 1, 2, 2, 3\}\)은 모두 같은 집합입니다. 파이썬의 set을 떠올리면 거의 그대로예요.

정의 4.1.1 (집합과 원소)

집합 \(A\)에 어떤 대상 \(x\)가 들어 있으면 \(x\)는 \(A\)의 원소(element)라 하고 \(x \in A\)라 씁니다. 들어 있지 않으면 \(x \notin A\)라 씁니다. 두 집합 \(A, B\)에 대해 \(A = B\)인 것은 정확히 같은 원소를 가질 때, 즉 \(\forall x\,(x \in A \iff x \in B)\)일 때입니다. 이것을 외연성 공리(axiom of extensionality)라 부릅니다.

집합을 적는 방법은 두 가지입니다. 원소를 그대로 나열하는 외연적 표기와, 조건으로 거르는 내포적 표기입니다. 예를 들어 \(\{2, 4, 6, 8\}\)은 외연적이고, \(\{n \in \mathbb{N} \mid n \text{이 짝수이고 } n \le 8\}\)은 내포적입니다. 후자는 "어떤 우주집합 \(\mathbb{N}\)에서 조건에 맞는 것만 골라낸다"는 뜻이에요.

특별한 집합 몇 개는 기호가 정해져 있습니다. \(\mathbb{N}\)은 자연수, \(\mathbb{Z}\)는 정수, \(\mathbb{Q}\)는 유리수, \(\mathbb{R}\)은 실수, \(\mathbb{C}\)는 복소수입니다. 그리고 원소가 하나도 없는 집합을 공집합(empty set)이라 하고 \(\emptyset\) 또는 \(\{\}\)로 씁니다. \(\emptyset\)은 단 하나뿐이라는 점이 중요합니다 (외연성 공리로부터 따라 나옵니다).

정의 4.1.2 (부분집합)

집합 \(A\)의 모든 원소가 \(B\)에도 들어 있으면 \(A\)는 \(B\)의 부분집합(subset)이라 하고 \(A \subseteq B\)라 씁니다. 즉 \(A \subseteq B \iff \forall x\,(x \in A \implies x \in B)\). 만약 \(A \subseteq B\)이면서 \(A \neq B\)라면 진부분집합(proper subset)이라 하고 \(A \subsetneq B\)라 씁니다.

두 집합이 서로 부분집합이면 같습니다. 이 사실은 의외로 자주 쓰여요. 어떤 집합이 다른 집합과 같다는 것을 직접 보이기 어려울 때, 양방향 포함을 따로따로 보이는 전략이 자연스럽게 나옵니다.

예제 4.1.3

\(A = \{1, 2\}\)의 모든 부분집합을 적어봅시다. \(\emptyset\), \(\{1\}\), \(\{2\}\), \(\{1, 2\}\) — 이렇게 네 개입니다. 일반적으로 원소가 \(n\)개인 집합은 부분집합이 \(2^n\)개예요. 각 원소를 "넣느냐 빼느냐" 두 가지로 정할 수 있고, 선택이 독립이니 \(2 \times 2 \times \cdots \times 2 = 2^n\)이 됩니다. 이 \(2^n\)이라는 숫자가 다음 정의와 바로 연결됩니다.

정의 4.1.4 (멱집합)

집합 \(A\)의 멱집합(power set)은 \(A\)의 모든 부분집합을 모은 집합입니다. \(\mathcal{P}(A) = \{S \mid S \subseteq A\}\). 예를 들어 \(\mathcal{P}(\{1, 2\}) = \{\emptyset, \{1\}, \{2\}, \{1, 2\}\}\)이고, \(|\mathcal{P}(A)| = 2^{|A|}\)입니다.

이제 집합끼리 섞고 빼는 연산을 봅시다. 두 집합 \(A, B\)에 대해

  • 합집합: \(A \cup B = \{x \mid x \in A \text{ 또는 } x \in B\}\)
  • 교집합: \(A \cap B = \{x \mid x \in A \text{ 그리고 } x \in B\}\)
  • 차집합: \(A \setminus B = \{x \mid x \in A \text{ 그리고 } x \notin B\}\)
  • 여집합: 어떤 우주집합 \(U\)가 정해져 있을 때 \(\overline{A} = U \setminus A\)

이 연산들은 명제논리의 ∨, ∧, ¬와 정확히 짝을 이룹니다. 그래서 명제논리의 항등식이 집합 항등식으로 그대로 옮겨가요. 예컨대 드모르간 법칙 \(\overline{A \cup B} = \overline{A} \cap \overline{B}\)는 \(\neg(p \lor q) \equiv \neg p \land \neg q\)의 집합 버전입니다.

예제 4.1.5

\(A = \{1, 2, 3, 4\}\), \(B = \{3, 4, 5, 6\}\), 우주 \(U = \{1, 2, \ldots, 8\}\)이라 합시다. 그러면 \(A \cup B = \{1, 2, 3, 4, 5, 6\}\), \(A \cap B = \{3, 4\}\), \(A \setminus B = \{1, 2\}\), \(\overline{A} = \{5, 6, 7, 8\}\). 직접 손으로 그려 보면 벤다이어그램이 보일 거예요.

노트: 러셀의 역설

"임의의 조건으로 집합을 만들 수 있다"고 무심코 가정하면 큰일 납니다. 다음을 보세요. \(R = \{x \mid x \notin x\}\) — 자기 자신을 원소로 가지지 않는 모든 것의 모임. 그러면 \(R \in R\)일까요? 만약 \(R \in R\)이라면 정의에 의해 \(R \notin R\). 반대로 \(R \notin R\)이라면 정의에 의해 \(R \in R\). 어느 쪽이든 모순이죠.

버틸런드 러셀이 1901년에 발견한 이 모순을 동네 이야기로 풀면 이렇습니다. "이 마을의 이발사는 스스로 면도하지 않는 사람들 모두를 면도하고, 오직 그들만 면도한다." 그럼 이발사는 스스로 면도하나요? 한다고 하면 정의에 어긋나고, 안 한다고 해도 어긋납니다. 답은 "그런 이발사는 존재하지 않는다"이고, 마찬가지로 "그런 집합 \(R\)은 존재하지 않는다"가 됩니다. 현대 수학은 이 문제를 ZFC 공리로 우회하지만, 우리는 일단 "조심히 만들면 됩니다" 정도로 넘어갑시다.

4.2 수열 Sequences

집합은 순서가 없습니다. 하지만 살다 보면 "1번, 2번, 3번"처럼 자리가 정해져 있는 모임이 필요할 때가 있어요. 사람 줄, 시간순 이벤트, 좌표 \((x, y)\) 같은 것들이죠. 그래서 수학자들은 수열(sequence) 또는 튜플(tuple)이라는 두 번째 자료구조를 만들었습니다.

정의 4.2.1 (수열)

수열은 원소를 순서 있게 늘어놓은 것입니다. 길이가 \(n\)인 수열은 \((a_1, a_2, \ldots, a_n)\)으로 적습니다. 두 수열이 같다는 것은 길이가 같고 같은 자리에 같은 원소가 있다는 뜻입니다. 즉 \((a_1, \ldots, a_n) = (b_1, \ldots, b_m)\) iff \(n = m\) 이고 모든 \(i\)에 대해 \(a_i = b_i\). 길이가 2인 수열은 특별히 순서쌍(ordered pair)이라 부릅니다.

집합과 수열의 차이를 분명히 해두겠습니다. \(\{1, 2\} = \{2, 1\}\)이지만 \((1, 2) \neq (2, 1)\)이에요. 또 \(\{1, 1\} = \{1\}\)이지만 \((1, 1) \neq (1)\)입니다. 한국어 강의에서 "튜플"이라는 말을 영어 그대로 쓸 때가 많은데, 본질은 순서 있는 모음입니다.

정의 4.2.2 (카르테시안 곱)

두 집합 \(A, B\)의 카르테시안 곱(Cartesian product)은 \(A\)에서 하나, \(B\)에서 하나 골라 만든 모든 순서쌍의 집합입니다. \[A \times B = \{(a, b) \mid a \in A,\ b \in B\}.\] 일반화해서 \(A_1 \times A_2 \times \cdots \times A_n\)은 \((a_1, \ldots, a_n)\)들의 집합으로, 각 \(a_i \in A_i\)를 만족합니다. \(A^n\)은 \(A \times A \times \cdots \times A\) (n번)을 가리킵니다.

예제 4.2.3

\(A = \{a, b\}\), \(B = \{1, 2, 3\}\)이면 \[A \times B = \{(a,1), (a,2), (a,3), (b,1), (b,2), (b,3)\}.\] 원소가 \(2 \times 3 = 6\)개죠. 일반적으로 유한집합이면 \(|A \times B| = |A| \cdot |B|\)입니다. 이게 곱셈을 "곱"이라 부르는 한 가지 이유고, 또 \(\mathbb{R}^2\)이 평면이 되는 이유이기도 합니다.

노트

프로그래머에게 \(A \times B\)는 "타입 \(A\)와 타입 \(B\)의 곱 타입"입니다. 하스켈의 (A, B), 러스트의 튜플, 파이썬의 tuple[A, B]가 모두 카르테시안 곱이에요. 마찬가지로 \(A^n\)은 길이 \(n\)인 \(A\)-원소 리스트로 보면 됩니다.

4.3 함수 Functions

이제 본격적인 무대입니다. 함수(function)는 "입력을 받으면 출력을 돌려주는 규칙"입니다. 고등학교에서 \(f(x) = x^2\) 같은 식으로 만났겠지만, 수학에서 함수를 정의할 때는 식이 있어야 한다고 요구하지 않습니다. 식 없이 그냥 "어떤 입력에 어떤 출력이 대응되는가"만 명시하면 충분합니다.

정의 4.3.1 (함수)

함수 \(f: A \to B\)는 \(A\)의 각 원소 \(a\)에 \(B\)의 원소 \(f(a)\)를 정확히 하나씩 대응시키는 규칙입니다. 이때 \(A\)를 \(f\)의 정의역(domain), \(B\)를 공역(codomain), \(\{f(a) \mid a \in A\}\)을 치역(image, range)이라 합니다.

여기서 두 가지를 강조하고 싶어요. 첫째, "정확히 하나씩"이 핵심입니다. 입력 하나에 출력이 두 개 나오면 함수가 아닙니다. 둘째, 공역과 치역은 다릅니다. 공역은 "출력이 살 수 있는 집"이고, 치역은 "실제로 살고 있는 집"입니다. 한국어 학생들이 자주 헷갈리는 지점이에요.

예제 4.3.2

\(f: \mathbb{R} \to \mathbb{R}\), \(f(x) = x^2\)을 봅시다. 정의역은 \(\mathbb{R}\), 공역도 \(\mathbb{R}\)이지만 치역은 \([0, \infty)\)입니다. 음수는 결코 출력으로 안 나오죠. 그래서 공역과 치역이 일치하지 않아요.

함수의 성격은 입출력의 짝짓기 패턴에 따라 세 가지로 분류됩니다.

정의 4.3.3 (단사, 전사, 전단사)

\(f: A \to B\)가

  • 단사(injective, one-to-one): 서로 다른 입력은 서로 다른 출력. 즉 \(\forall a_1, a_2 \in A,\ a_1 \neq a_2 \implies f(a_1) \neq f(a_2)\). 동치로 \(f(a_1) = f(a_2) \implies a_1 = a_2\).
  • 전사(surjective, onto): 공역의 모든 원소가 적어도 하나의 입력에서 나옴. 즉 \(\forall b \in B,\ \exists a \in A,\ f(a) = b\). 즉 치역 = 공역.
  • 전단사(bijective): 단사이면서 전사. 입출력이 완벽하게 일대일 대응.

그림으로 보면 직관이 더 빠릅니다.

   단사 (injective)        전사 (surjective)       전단사 (bijective)
   ------------------     -------------------     -------------------
   A         B            A         B             A         B
   1 ──────► a            1 ──────► a             1 ──────► a
   2 ──────► b            2 ─┐                    2 ──────► b
   3 ──────► c            3 ─┴────► b             3 ──────► c
             d (남음)                  c
   서로 다른 → 서로 다른     모든 b가 화살을 받음       둘 다 만족

단사는 "겹치지 않는다", 전사는 "남는 게 없다", 전단사는 "둘 다"라고 외워두면 좋아요. 영어로는 "into" vs "onto"라는 표현도 자주 등장하는데, "into"는 그냥 함수, "onto"는 전사를 가리킵니다.

예제 4.3.4

\(f: \mathbb{Z} \to \mathbb{Z}\), \(f(n) = n + 1\)는 전단사입니다. 다른 입력은 다른 출력을 주니 단사이고, 임의의 \(m \in \mathbb{Z}\)에 대해 \(f(m - 1) = m\)이니 전사. 반면 \(g: \mathbb{Z} \to \mathbb{Z}\), \(g(n) = n^2\)는 단사도 전사도 아니에요. \(g(1) = g(-1) = 1\)이니 단사 X, 출력 -1이 안 나오니 전사 X.

노트

함수가 전단사면 역함수(inverse)가 잘 정의됩니다. \(f^{-1}: B \to A\)가 \(f^{-1}(b) = a \iff f(a) = b\)로 자연스럽게 만들어져요. 단사가 아니면 한 출력에 입력이 여러 개일 수 있어 역이 함수가 안 되고, 전사가 아니면 역의 정의역 일부에서 값을 못 정합니다. 그래서 "역함수의 존재 = 전단사" 입니다.

4.4 이항관계 Binary Relations

함수보다 더 일반적인 개념이 이항관계입니다. 직관적으로 "이 두 원소는 어떤 식으로든 관련이 있다"를 가리키는 표시예요. 예를 들어 정수에서 \(\le\), 사람들 사이에서 "친구다", 도시들 사이에서 "직항이 있다" 같은 것들이 모두 이항관계입니다.

정의 4.4.1 (이항관계)

집합 \(A, B\) 사이의 이항관계(binary relation)는 카르테시안 곱 \(A \times B\)의 부분집합입니다. 즉 \(R \subseteq A \times B\). \((a, b) \in R\)일 때 흔히 \(a\,R\,b\)라 적습니다. \(A = B\)인 경우 "\(A\) 위의 관계"라 부릅니다.

처음 보면 "관계가 부분집합이라고?" 하고 갸웃할 수 있어요. 이렇게 생각해 보세요. 어떤 두 원소가 관계가 있느냐 없느냐는 결국 yes/no 질문이고, 관련 있는 쌍들만 모아두면 그게 곧 \(A \times B\)의 부분집합이 됩니다. 모든 쌍에 대해 한 번씩 답을 적어둔 표가 바로 \(R\)이에요.

예제 4.4.2

\(A = \{1, 2, 3\}\) 위에서 "나누어 떨어진다" 관계를 \(R\)이라 합시다. 즉 \(a\,R\,b \iff a \mid b\). 그러면 \[R = \{(1,1), (1,2), (1,3), (2,2), (3,3)\}.\] 1은 모든 수를 나누고, 2는 자기만 나누고 (3을 못 나눔), 3도 자기만 나눕니다.

정리 4.4.3 (함수는 특수한 관계다)

모든 함수 \(f: A \to B\)는 그 그래프 \(\Gamma_f = \{(a, f(a)) \mid a \in A\} \subseteq A \times B\)로 표현되는 관계입니다. 거꾸로, 관계 \(R \subseteq A \times B\)가 다음 두 조건을 만족하면 함수입니다.

  • 전체성: 모든 \(a \in A\)에 대해 어떤 \(b \in B\)가 \((a, b) \in R\).
  • 유일성: \((a, b_1), (a, b_2) \in R\)이면 \(b_1 = b_2\).

다시 말해 함수는 "왼쪽 입력마다 짝이 정확히 하나"인 관계입니다. 관계 일반은 짝이 0개여도, 여러 개여도 괜찮아요. 그래서 함수는 관계의 "엄격한 부분집합"인 거죠.

정의 4.4.4 (관계의 합성과 역)

관계 \(R \subseteq A \times B\)와 \(S \subseteq B \times C\)에 대해 합성 \(S \circ R \subseteq A \times C\)는 \[S \circ R = \{(a, c) \mid \exists b \in B,\ (a, b) \in R \text{ 그리고 } (b, c) \in S\}.\] 또 관계 \(R \subseteq A \times B\)의 역(inverse)은 \(R^{-1} = \{(b, a) \mid (a, b) \in R\} \subseteq B \times A\).

합성은 화살표를 이어 붙이는 것입니다. \(a\)에서 \(R\) 화살을 따라가서 \(b\)에 도착하고, 거기서 \(S\) 화살을 따라가서 \(c\)에 도착할 수 있다면 \((a, c)\)는 합성 관계에 들어갑니다. 함수의 합성 \((g \circ f)(x) = g(f(x))\)이 바로 이 일반 정의의 특수한 경우예요.

역도 마찬가지입니다. 일반 관계의 역은 항상 잘 정의됩니다 (그냥 쌍을 뒤집으면 끝). 하지만 함수의 역은 전단사일 때만 함수가 된다고 했죠. 그게 바로 관계와 함수의 차이를 보여주는 좋은 예입니다.

예제 4.4.5

사람 집합 \(P\) 위에 "부모다" 관계 \(R\)을 둡시다. \(a\,R\,b\)는 "\(a\)는 \(b\)의 부모". 그러면 \(R^{-1}\)은 "자식이다" 관계가 됩니다. 또 \(R \circ R\)은 "조부모다" 관계예요 — \(a\)가 \(b\)의 부모이고 \(b\)가 \(c\)의 부모이면 \(a\)는 \(c\)의 조부모니까요. 이렇게 합성과 역으로 새 관계를 만들어가는 게 5장에서 다룰 동치관계, 순서관계의 토대가 됩니다.

4.5 유한 기수 Finite Cardinality

마지막은 "집합의 크기"입니다. 유한집합의 크기는 그냥 원소의 개수예요. 직관적으로는 너무 당연해서 정의할 필요가 있나 싶지만, 큰 집합이나 무한집합으로 가면 "크기"라는 말 자체가 엄밀해야 합니다. 이 챕터에서는 유한 케이스만 다루고, 무한집합의 기수는 한참 뒤(15장쯤)에서 다시 등장합니다.

정의 4.5.1 (유한 기수)

유한집합 \(A\)의 기수(cardinality) \(|A|\)는 \(A\)의 원소 개수입니다. 예를 들어 \(|\emptyset| = 0\), \(|\{a, b, c\}| = 3\), \(|\{1, 2\} \times \{x, y, z\}| = 6\), \(|\mathcal{P}(\{1, 2, 3\})| = 2^3 = 8\).

기수의 산수에는 몇 가지 기본 규칙이 있어요.

  • \(|A \cup B| = |A| + |B| - |A \cap B|\) (포함-배제 원리, 11장에서 자세히)
  • \(|A \times B| = |A| \cdot |B|\)
  • \(|A^n| = |A|^n\)
  • \(|\mathcal{P}(A)| = 2^{|A|}\)

이걸 함수의 단사/전사로 다시 쓸 수 있습니다. 유한집합 \(A, B\) 사이에 단사 \(f: A \to B\)가 있다면 \(A\)의 원소들이 \(B\) 안으로 겹치지 않게 들어간 것이니 \(|A| \le |B|\)예요. 거꾸로 전사 \(g: A \to B\)가 있다면 \(B\)의 모든 원소가 화살을 받았으니 \(A\)가 그것들을 모두 만들어낼 수 있어야 하고, 그래서 \(|A| \ge |B|\). 그리고 전단사가 있다면 \(|A| = |B|\).

정리 4.5.2 (기수 비교)

유한집합 \(A, B\)에 대해

  • 단사 \(A \to B\)가 존재 \(\iff |A| \le |B|\)
  • 전사 \(A \to B\)가 존재 \(\iff |A| \ge |B|\) (단, \(A \neq \emptyset\))
  • 전단사 \(A \to B\)가 존재 \(\iff |A| = |B|\)

이 정리가 강력한 이유는, 크기를 직접 세지 않고도 함수를 만들어 비교할 수 있다는 점입니다. 무한집합으로 일반화할 때 진짜 빛을 발해요. "두 집합이 같은 크기다"를 "전단사가 있다"로 정의하는 게 칸토어의 통찰이었거든요.

정리 4.5.3 (비둘기집 원리)

유한집합 \(A, B\)에 대해 \(|A| > |B|\)라면 어떤 함수 \(f: A \to B\)도 단사일 수 없다. 즉 \(f(a_1) = f(a_2)\)인 서로 다른 \(a_1, a_2 \in A\)가 반드시 존재한다.

증명 (스케치)

대우로 보이면 됩니다. \(f\)가 단사라 가정하면 정리 4.5.2에 의해 \(|A| \le |B|\)이므로 \(|A| > |B|\)에 모순. ∎

이름이 귀엽죠. "비둘기집(pigeonhole) 원리"라 부르는 이유는, 비둘기 \(n+1\)마리를 둥지 \(n\)개에 넣으면 어떤 둥지에는 비둘기가 두 마리 이상 들어간다는 그림으로 외우면 쉽기 때문입니다. 단순해 보이지만 조합론, 그래프이론, 알고리즘 분석 곳곳에서 결정적으로 쓰이는 무기예요. 11장에서 본격적으로 다시 만납니다.

예제 4.5.4

서울 시민 중 머리카락 수가 똑같은 사람이 적어도 두 명 있을까요? 사람 머리카락은 보통 15만 개를 넘지 않습니다. 그러니 \(B = \{0, 1, \ldots, 200{,}000\}\)이라 두면 \(|B| = 200{,}001\). 서울 인구는 900만 명이 넘으니 \(|A| > |B|\). 비둘기집 원리에 의해 머리카락 수가 같은 사람이 무수히 많이 존재합니다. 직관적으로는 별것 아닌 결론 같지만, 직접 세지 않고 순수히 크기만으로 결론을 끌어낸 게 포인트예요.

맺음말

이 챕터에서 우리는 수학자의 자료구조 네 가지(집합, 수열, 함수, 관계)에 크기 개념까지 얹어봤습니다. 앞으로 등장하는 거의 모든 정의가 이 위에서 굴러갑니다. 그래프는 정점집합과 간선관계의 짝, 동치류는 관계의 한 종류, 수열은 \(\mathbb{N}\)에서 어떤 집합으로 가는 함수 등등. 컴퓨터과학에서도 마찬가지로 set/list/map/그래프 자료구조가 정확히 이 추상에 대응됩니다. 익숙해질 때까지는 손으로 작은 예제를 자꾸 그려보세요. 손에 붙는 만큼 5장 이후가 편해집니다.

PART I — 증명

5 수학적 귀납법 Induction

수학적 귀납법은 유한한 한두 페이지짜리 증명으로 무한히 많은 명제를 한꺼번에 잡는 마법 같은 도구입니다. 이번 챕터에서는 일반 귀납법, 강한 귀납법, 정렬원리(well-ordering)라는 세 가지 동치인 원리를 차근차근 살펴보고, 왜 이 셋이 사실은 같은 이야기를 하는지를 풀어봅니다. 또한 학생들이 흔히 빠지는 함정 — 그 유명한 "모든 말은 같은 색이다" 같은 잘못된 귀납 — 도 함께 해부하며, 귀납이라는 도구를 손에 익혀봅시다.

5.1 일반 귀납법 Ordinary Induction

자연수 \( n \)에 대해 어떤 명제 \( P(n) \)이 모두 참이라는 사실을 증명하고 싶다고 합시다. 무한히 많은 \( n \)을 하나하나 검사할 수는 없습니다. 이때 등장하는 묘책이 바로 귀납법입니다.

가장 흔한 비유는 도미노입니다. 길게 늘어선 도미노가 무한히 있어요. 우리가 보장하고 싶은 건 "모든 도미노가 결국 쓰러진다"는 사실입니다. 그러려면 두 가지만 확인하면 충분합니다. 첫째, 첫 번째 도미노를 우리가 직접 손가락으로 밀어 쓰러뜨립니다. 둘째, 임의의 \( k \)번째 도미노가 쓰러지면 \( k+1 \)번째도 반드시 쓰러진다는 보장이 있습니다. 이 두 가지가 동시에 성립하면, 첫 번째 도미노가 두 번째를 쓰러뜨리고, 두 번째가 세 번째를 쓰러뜨리고… 끝없이 이어져 모든 도미노가 쓰러집니다. 한 번도 손대지 않은 백만 번째 도미노조차도요.

이 직관을 그대로 수학 언어로 옮긴 것이 일반 귀납법입니다.

원리 5.1.1 (일반 귀납법, Induction)

자연수 \( n \in \mathbb{N} = \{0, 1, 2, \ldots\} \)에 대한 명제 \( P(n) \)이 다음 두 조건을 만족한다고 하자.

(1) 기저 단계 (base case): \( P(0) \)이 참이다.

(2) 귀납 단계 (inductive step): 임의의 \( k \ge 0 \)에 대해 \( P(k) \implies P(k+1) \)이 참이다.

그러면 모든 자연수 \( n \)에 대해 \( P(n) \)이 참이다.

여기서 귀납 단계의 \( P(k) \)를 귀납 가설(induction hypothesis)이라고 부릅니다. 증명을 쓸 때 우리는 보통 "어떤 \( k \)에 대해 \( P(k) \)가 성립한다고 가정하자"라고 운을 떼고, 그 가정으로부터 \( P(k+1) \)을 끌어냅니다. 가정을 일단 하나 사 놓고, 그것을 사다리 삼아 한 칸 위로 올라가는 것이라고 봐도 됩니다.

예제 5.1.2 (가우스의 합 공식)

모든 자연수 \( n \ge 1 \)에 대해 다음이 성립함을 보입시다.

\[ 1 + 2 + 3 + \cdots + n = \frac{n(n+1)}{2}. \]

풀이. \( P(n) \)을 위 등식이라고 두자.

(기저 단계) \( n = 1 \)일 때 좌변은 \( 1 \), 우변은 \( \frac{1 \cdot 2}{2} = 1 \). 같다. \( P(1) \) 참.

(귀납 단계) \( P(k) \)가 참이라고 가정하자. 즉 \( 1 + 2 + \cdots + k = \frac{k(k+1)}{2} \)라고 하자. 이때 \( P(k+1) \), 다시 말해 \( 1 + 2 + \cdots + k + (k+1) = \frac{(k+1)(k+2)}{2} \)임을 보이면 된다.

좌변을 귀납 가설로 치환하면

\[ \underbrace{1 + 2 + \cdots + k}_{\text{귀납 가설}} + (k+1) = \frac{k(k+1)}{2} + (k+1) = \frac{k(k+1) + 2(k+1)}{2} = \frac{(k+1)(k+2)}{2}. \]

이는 정확히 \( P(k+1) \)의 우변이다. 따라서 \( P(k) \implies P(k+1) \).

두 단계가 모두 성립하므로 모든 \( n \ge 1 \)에 대해 \( P(n) \)이 참이다. ∎

처음 보면 "어? 이게 정말로 모든 \( n \)을 증명하는 거 맞아?"라는 의심이 들 수 있습니다. 그도 그럴 것이, 우리는 어디에서도 "구체적인 \( n=27 \)일 때"를 따로 증명하지 않았으니까요. 비밀은 도미노의 사슬에 있습니다. \( P(1) \)이 참이고, \( P(1) \implies P(2) \)이니 \( P(2) \)도 참. 이어서 \( P(2) \implies P(3) \)이니 \( P(3) \)도 참. 이렇게 27단계를 거치면 \( P(27) \)에 도달합니다. 우리가 증명에서 한 일은 사실상 "어떤 \( k \)를 가져와도 다음 칸으로 넘어갈 수 있는 보편적인 한 줄짜리 사다리"를 만든 것이고, 그 사다리가 무한히 반복 사용 가능하기 때문에 모든 \( n \)이 자동으로 따라옵니다.

예제 5.1.3 (홀수의 합)

또 하나의 고전 예제로, 처음 \( n \)개의 홀수의 합이 완전제곱이 됨을 봅시다.

\[ 1 + 3 + 5 + \cdots + (2n-1) = n^2 \quad (n \ge 1). \]

(기저) \( n=1 \): 좌변 \( 1 \), 우변 \( 1^2 = 1 \). 참.

(귀납) \( 1 + 3 + \cdots + (2k-1) = k^2 \)이라고 가정하자. 양변에 \( 2(k+1)-1 = 2k+1 \)을 더하면

\[ 1 + 3 + \cdots + (2k-1) + (2k+1) = k^2 + 2k + 1 = (k+1)^2. \]

이는 \( P(k+1) \)의 형태이다. ∎

이제 학생들에게 정말 깊이 새겨야 할 위험한 함정을 하나 보여드리겠습니다. 귀납법의 두 단계 중 어느 한 곳이라도 부주의하면 명백히 거짓인 명제도 "증명"되는 듯 보인다는 점입니다.

주의: 모든 말은 같은 색이다(?)

다음은 유명한 잘못된 귀납입니다. \( P(n) \)을 "임의의 말 \( n \)마리는 모두 같은 색이다"라고 정의합시다.

(기저) \( n=1 \): 한 마리뿐이니 자기 자신과 같은 색. 자명.

(귀납) \( P(k) \)가 참이라고 가정. 말 \( k+1 \)마리를 일렬로 세워보자: \( h_1, h_2, \ldots, h_{k+1} \).

앞쪽 \( k \)마리 \( \{h_1, \ldots, h_k\} \)는 귀납 가설로 모두 같은 색.

뒤쪽 \( k \)마리 \( \{h_2, \ldots, h_{k+1}\} \)도 귀납 가설로 모두 같은 색.

두 집합은 \( h_2 \)부터 \( h_k \)까지 겹치므로, "같은 색"이라는 성질이 전염되어 모두 한 색!

따라서 모든 자연수 \( n \)에 대해 임의의 말 \( n \)마리는 같은 색. 결론: 세상 모든 말은 같은 색.

물론 결론은 거짓입니다. 어디가 잘못됐을까요? 핵심은 \( k=1 \)에서 \( k+1=2 \)로 넘어갈 때입니다. 말 두 마리 \( h_1, h_2 \)의 경우, 앞 1마리 집합은 \( \{h_1\} \), 뒤 1마리 집합은 \( \{h_2\} \). 두 집합은 겹치는 원소가 없습니다. "같은 색"을 전염시킬 다리가 없는 거예요. 즉 귀납 단계가 \( k \ge 2 \)일 때만 동작하는데, 우리는 그것을 모든 \( k \ge 1 \)에 대해 성립한다고 슬쩍 가정해버렸습니다. 도미노 사슬에 한 칸 빠진 곳이 있으면 그 너머는 무너지지 않습니다.

이 함정의 교훈은 분명합니다. 귀납 단계가 "모든 \( k \)에 대해" 성립한다고 주장할 때, 우리가 사용한 모든 보조 사실(여기서는 두 집합의 교집합이 비지 않는다는 사실)이 정말로 모든 \( k \)에서 통하는지 검증해야 합니다. 작은 \( k \)에서 한 번이라도 사슬이 끊기면 전체 증명이 무너집니다.

5.2 강한 귀납법 Strong Induction

일반 귀납법은 \( P(k) \) 하나만으로 \( P(k+1) \)을 끌어내는 방식이었습니다. 그러나 어떤 명제는 한 칸 전이 아니라 지금까지 쌓아온 모든 결과를 동시에 활용해야 다음 칸을 증명할 수 있습니다. 이때 등장하는 게 강한 귀납법(strong induction)입니다. 이름이 거창하지만 사실은 가설을 더 풍부하게 사용해도 된다는 허락일 뿐이에요.

원리 5.2.1 (강한 귀납법)

자연수에 대한 명제 \( P(n) \)이 다음 두 조건을 만족한다고 하자.

(1) 기저 단계: \( P(0) \)이 참이다.

(2) 귀납 단계: 임의의 \( k \ge 0 \)에 대해, \( P(0), P(1), \ldots, P(k) \)이 모두 참이라고 가정하면 \( P(k+1) \)도 참이다.

그러면 모든 자연수 \( n \)에 대해 \( P(n) \)이 참이다.

일반 귀납법과의 차이를 다시 강조하자면, 귀납 가설로 사용할 수 있는 정보의 폭이 다릅니다. 일반 귀납법은 직전 한 칸 \( P(k) \)만 손에 쥐고 \( P(k+1) \)을 만들지만, 강한 귀납법은 \( P(0) \)부터 \( P(k) \)까지 전부 손에 쥐고 \( P(k+1) \)을 만듭니다. 무기고가 더 빵빵해진 셈이죠. 그래서 "더 강한" 귀납법이라고 부릅니다. 도미노 비유로는, 다음 도미노를 쓰러뜨릴 때 단지 직전 한 개의 도미노가 부딪힌 충격만이 아니라, 지금까지 쓰러진 모든 도미노가 만들어낸 누적 효과를 활용해도 된다는 뜻입니다.

강한 귀납법이 진가를 발휘하는 대표적인 예가 바로 정수론의 출발점, 소인수분해 존재성입니다.

정리 5.2.2 (소인수분해의 존재)

2 이상의 모든 자연수 \( n \)은 유한 개의 소수의 곱으로 표현할 수 있다. 즉 어떤 소수들 \( p_1, p_2, \ldots, p_m \)이 존재하여 \( n = p_1 p_2 \cdots p_m \)이다.

증명 (강한 귀납법)

\( P(n) \)을 "\( n \)이 소수들의 곱으로 표현 가능하다"는 명제라고 두자. \( n \ge 2 \)에 대해 강한 귀납법으로 증명한다.

(기저) \( n = 2 \): 2 자체가 소수이다. 자기 자신을 길이 1의 곱으로 보면 \( 2 = 2 \). 따라서 \( P(2) \) 참.

(귀납) 어떤 \( k \ge 2 \)에 대해 \( P(2), P(3), \ldots, P(k) \)이 모두 참이라고 가정하자. \( P(k+1) \)을 보이자. 즉 \( k+1 \)이 소수들의 곱임을 보이자.

경우를 나눈다.

(i) \( k+1 \)이 소수인 경우. 그 자체가 소수의 곱이므로 \( P(k+1) \) 참.

(ii) \( k+1 \)이 합성수인 경우. 정의상 \( k+1 = a \cdot b \)이고 \( 2 \le a \le b \le k \)인 자연수 \( a, b \)가 존재한다. 이때 \( a, b \)는 모두 \( k \) 이하이므로, 귀납 가설에 의해 \( a \)와 \( b \)는 각각 소수의 곱으로 표현된다. 두 표현을 이어 붙이면 \( k+1 = a \cdot b \) 또한 소수의 곱이다. 즉 \( P(k+1) \) 참.

두 경우 모두 성립하므로 귀납이 끝난다. ∎

여기서 결정적인 점은, \( P(k+1) \)을 증명하기 위해 우리가 \( P(k) \)가 아니라 \( P(a) \)와 \( P(b) \)를 가져다 썼다는 사실입니다. \( a \)와 \( b \)는 \( k+1 \)보다 작은 어떤 값일 뿐, 정확히 \( k \)는 아닙니다. 일반 귀납법에서는 직전 한 칸의 결과만 사용 가능하므로 이런 식의 증명을 곧장 쓰기가 어색하지만, 강한 귀납법에서는 자연스럽습니다.

예제 5.2.3 (체스 토너먼트 우승 트리)

\( n \)명의 선수가 토너먼트로 단판 승부를 합니다. 매 경기 후 한 명이 탈락한다고 할 때, 우승자가 결정되기까지 정확히 \( n-1 \)번의 경기가 필요함을 보입시다.

풀이. \( P(n) \): "\( n \)명 토너먼트에는 정확히 \( n-1 \)번의 경기가 있다."

(기저) \( n = 1 \): 경기 0번. 참.

(귀납) \( P(1), \ldots, P(k) \)가 참이라고 하자. \( k+1 \)명 토너먼트의 결승전 직전을 보면, 두 그룹 \( a \)명과 \( b \)명에서 각각 우승자가 결정되어 결승에 올라간다고 볼 수 있다 (\( a + b = k+1 \), \( 1 \le a, b \le k \)). 귀납 가설로 두 그룹은 각각 \( a-1 \), \( b-1 \)번의 경기를 거친다. 마지막 결승까지 더하면 \( (a-1) + (b-1) + 1 = a+b-1 = k \)번의 경기. 따라서 \( P(k+1) \) 참. ∎

한 가지 더 강조할 점이 있습니다. 강한 귀납법과 일반 귀납법은 결국 같은 결론을 증명할 수 있다는 의미에서 동치입니다. 강한 귀납법으로 증명되는 모든 명제는 일반 귀납법으로도 증명할 수 있고, 그 반대도 마찬가지입니다. 다만 강한 귀납법으로 쓰면 증명이 자연스럽고 깔끔해지는 경우가 많을 뿐입니다.

노트: 왜 동치인가

강한 귀납법으로 \( P(n) \)을 증명하고 싶다고 합시다. 새 명제 \( Q(n) := P(0) \land P(1) \land \cdots \land P(n) \)을 정의하면, \( Q \)에 대해 일반 귀납법을 써서 증명할 수 있습니다. \( Q(k) \implies Q(k+1) \)을 보이는 일이 곧 강한 귀납법의 귀납 단계와 같으니까요. 이렇게 가설을 묶어두는 트릭만으로 일반 귀납법이 강한 귀납법을 흉내낼 수 있습니다. 반대 방향은 더 자명합니다 — 강한 귀납법은 일반 귀납법의 가설을 포함하니까 더 적은 정보만 쓰면 일반 귀납과 다를 게 없습니다.

실전에서는 "이 문제는 일반 귀납이냐 강한 귀납이냐"를 너무 고민하지 말고, 증명 도중 \( k+1 \) 이전의 어떤 값을 가져다 쓰고 싶어지는지를 보고 자연스럽게 강한 귀납을 쓰면 됩니다. 컴퓨터과학에서 분할정복 알고리즘의 정당성 증명, 재귀 호출의 종료 증명, 자료구조의 불변식 증명 같은 데서 강한 귀납법이 거의 표준적으로 등장합니다.

5.3 강귀납 vs 일반 귀납 vs 정렬원리 Strong Induction vs. Induction vs. Well Ordering

4장에서 우리는 정렬원리(Well Ordering Principle)를 만났습니다. 다시 적어두면 다음과 같습니다.

원리 5.3.1 (정렬원리, Well Ordering Principle)

자연수 \( \mathbb{N} \)의 공집합이 아닌 모든 부분집합 \( S \subseteq \mathbb{N} \)는 최소 원소를 가진다.

그리고 이번 챕터에서 일반 귀납법과 강한 귀납법을 만났습니다. 놀랍게도 이 셋은 서로 동치입니다. 즉 셋 중 어느 하나라도 자연수 체계의 공리로 받아들이면 나머지 둘이 따라옵니다. "다른 모자를 쓴 같은 사람"이라고 부를 만합니다.

정리 5.3.2 (세 원리의 동치)

다음 세 명제는 자연수 \( \mathbb{N} \)에서 서로 동치이다.

(WO) 정렬원리

(SI) 강한 귀납법

(I) 일반 귀납법

증명의 큰 그림을 먼저 보고 갑시다. 서로 동치임을 보이려면 일반적으로 셋을 한 사이클로 잇는 함의를 보입니다. 즉

   ┌─── (WO) ───┐
   │            │
   ▼            │
  (SI)          │
   │            │
   ▼            │
   (I) ─────────┘
    

방향으로 \( (WO) \implies (SI) \implies (I) \implies (WO) \)를 보이면, 어느 둘 사이의 함의도 사이클을 한 바퀴 돌아 얻을 수 있습니다.

증명 스케치

(WO) ⇒ (SI): 정렬원리를 가정. 어떤 \( P \)가 강한 귀납법의 두 조건(기저, 강한 귀납 단계)을 만족한다고 하자. \( P \)가 모든 자연수에서 참임을 보이고 싶다.

모순법을 쓰자. 만약 어떤 \( n \)에서 \( P(n) \)이 거짓이라고 하면, 반례 집합 \( S = \{ n \in \mathbb{N} : \lnot P(n) \} \)은 공집합이 아니다. 정렬원리로 \( S \)는 최소 원소 \( m \)을 가진다. \( m \neq 0 \)이다 (왜냐하면 기저 단계로 \( P(0) \)이 참). 따라서 \( m \ge 1 \), 그리고 \( m \)이 \( S \)의 최솟값이라는 사실에서 \( P(0), P(1), \ldots, P(m-1) \)은 모두 참. 그러면 강한 귀납 단계로 \( P(m) \)도 참이 되어야 하는데, 이는 \( m \in S \)와 모순이다. 따라서 \( S \)는 공집합이고 \( P \)는 어디서나 참이다.

(SI) ⇒ (I): 강한 귀납법을 가정. 어떤 \( P \)가 일반 귀납법의 두 조건을 만족한다고 하자. 그러면 특히 \( P(k) \implies P(k+1) \)이 성립하므로, "\( P(0), \ldots, P(k) \)가 모두 참"이라는 더 강한 가정으로부터도 당연히 \( P(k+1) \)이 따라온다 (사용 안 하는 가설이 늘었을 뿐). 그러므로 강한 귀납법의 두 조건도 만족하고, 강한 귀납법으로 \( P \)는 모든 \( n \)에서 참.

(I) ⇒ (WO): 일반 귀납법을 가정. 정렬원리를 보이고 싶다. 즉 공집합이 아닌 \( S \subseteq \mathbb{N} \)에 대해 최솟값이 존재함을 보이자.

대우로 가자. \( S \)에 최솟값이 없다고 가정하고 \( S = \emptyset \)임을 증명한다. 명제 \( Q(n) := \) "\( 0, 1, \ldots, n \)은 모두 \( S \)에 속하지 않는다"라고 정의하자. 이를 \( n \)에 대한 일반 귀납법으로 증명하면 \( Q \)가 모든 자연수에서 참, 즉 \( S \)에 어떤 자연수도 들어갈 수 없게 되어 \( S = \emptyset \)이 된다.

(기저) \( n=0 \): 만약 \( 0 \in S \)라면 0은 자연수의 최솟값이므로 \( S \)의 최솟값이 된다. 이는 가정에 어긋나므로 \( 0 \notin S \). 따라서 \( Q(0) \) 참.

(귀납) \( Q(k) \) 참이라고 하자, 즉 \( 0, 1, \ldots, k \)는 모두 \( S \)에 없다. \( k+1 \in S \)라면 \( k+1 \)은 \( S \)의 가장 작은 원소가 된다 (\( S \) 안에 \( k+1 \)보다 작은 원소가 \( k \) 이하 자연수 중 없으므로). 가정과 모순. 따라서 \( k+1 \notin S \)이며 \( Q(k+1) \) 참.

일반 귀납법으로 \( Q(n) \)이 모든 \( n \)에서 참, 즉 \( S = \emptyset \). ∎

이 사이클이 보여주는 바는 강력합니다. 자연수 위의 명제를 증명할 때 어떤 도구를 고를지는 사실 스타일의 문제이지 능력의 문제가 아닙니다. 정렬원리로 풀리는 모든 문제는 일반 귀납법으로도 풀 수 있고, 강한 귀납법으로 풀리는 모든 문제는 정렬원리로도 풀 수 있습니다. 다만 어떤 문제는 한쪽 옷이 더 잘 맞을 뿐이에요.

노트: 어떤 옷을 언제 입을까

대략적인 경험칙을 적어두면 다음과 같습니다.

(가) 닫힌 형태의 등식(예: \( \sum_{i=1}^n i = \frac{n(n+1)}{2} \))처럼 한 칸씩 차곡차곡 쌓이는 증명에는 일반 귀납법이 가장 깔끔합니다.

(나) 합성/분해를 동반하는 명제(소인수분해, 분할정복 알고리즘, 트리·그래프의 구조 분해)에는 강한 귀납법이 자연스럽습니다. 작은 부분문제로 쪼개진 결과들을 모두 끌어오는 일이 빈번하니까요.

(다) "이런 게 존재할 수 없다"식의 부정적 결론(예: 무리수성 증명, 무한강하법, 알고리즘 종료성 증명)에는 정렬원리가 단정합니다. "최소 반례를 잡고 그것이 또 작은 반례를 만들어내 모순"이라는 무한강하 패턴이 정렬원리 위에서 가장 자연스럽기 때문입니다.

마지막으로 한 가지 직관을 덧붙이고 싶습니다. 자연수가 "잘 정렬된" 집합이라는 사실 — 즉 비어 있지 않은 어떤 부분집합도 반드시 가장 작은 원소를 가진다는 사실 — 은 자연수 체계의 가장 본질적인 성질 중 하나입니다. 도미노가 줄지어 있다는 그림과, 부분집합에 항상 출발점이 있다는 그림은 결국 같은 그림의 두 얼굴입니다. 한쪽은 "처음을 미는 손가락"의 관점이고, 다른 한쪽은 "가장 처음에 있는 도미노"의 관점입니다. 우리가 원리 셋을 자유자재로 오갈 수 있게 되는 순간, 이 두 얼굴이 하나의 얼굴로 보이기 시작합니다.

이번 챕터의 도구들은 앞으로 그래프 이론, 알고리즘, 수론, 형식언어 어디에서나 다시 만날 겁니다. 한 번에 다 익숙해지지 않더라도, 새 단원에서 귀납을 다시 마주칠 때마다 이 챕터로 돌아와 도미노와 정렬, 그리고 "유한한 손가락질로 무한을 다루는 마법"을 떠올려보길 권합니다.

PART I — 증명

6 상태 기계 State Machines

컴퓨터 프로그램은 결국 무엇일까요? 추상적으로 보면 프로그램은 하나의 거대한 상태 기계입니다. 어떤 시작 상태에서 출발해, 한 걸음씩 정해진 규칙대로 다음 상태로 이동하는 시스템이지요. 이 챕터에서는 상태 기계라는 모델을 정식으로 정의하고, 5장에서 배운 귀납을 다시 변주해서 "프로그램이 정말로 옳게 작동하는가"를 증명하는 도구를 만듭니다. 마지막에는 그 도구로 누구나 한 번쯤 들어봤을 안정 결혼 알고리즘까지 분석합니다.

6.1 상태와 전이 States and Transitions

일상적인 비유부터 시작해 봅시다. 신호등은 빨강, 노랑, 초록 세 가지 "상태"를 갖고, 일정한 규칙에 따라 한 색에서 다음 색으로 바뀝니다. 자판기는 동전을 넣은 만큼의 "잔고 상태"를 기억하고, 버튼을 누르거나 동전을 더 넣을 때마다 상태가 변합니다. 이런 시스템들의 공통점은 (1) 가능한 상태들의 집합이 명확하고, (2) 한 상태에서 다른 상태로 가는 규칙이 정해져 있다는 점이에요. 우리가 다루는 알고리즘이나 프로그램도 본질적으로 똑같습니다.

정의 6.1.1 (상태 기계)

상태 기계(state machine)는 다음 세 가지로 구성된 구조 \( M = (Q, q_0, \delta) \)입니다.

(1) 상태 집합 \( Q \) — 가능한 모든 상태들의 모음. 유한해도 되고 무한해도 됩니다.
(2) 시작 상태 \( q_0 \in Q \) — 기계가 처음 놓이는 상태.
(3) 전이 관계 \( \delta \subseteq Q \times Q \) — 한 걸음에 갈 수 있는 (현재 상태, 다음 상태) 쌍의 집합. \( (q, q') \in \delta \)이면 \( q \to q' \)로 씁니다.

전이를 함수로 보지 않고 관계로 정의한 이유는, 같은 상태에서 여러 다음 상태로 갈 수 있는 비결정적(nondeterministic) 시스템도 다루기 위해서예요. 만약 모든 \( q \)에 대해 \( q \to q' \)인 \( q' \)가 정확히 하나뿐이면, 이를 결정적(deterministic) 상태 기계라 부릅니다.

정의 6.1.2 (실행과 도달 가능성)

상태 기계 \( M \)의 실행(execution)은 다음을 만족하는 상태들의 (유한 또는 무한) 수열입니다.

\[ q_0 \to q_1 \to q_2 \to \cdots \]

여기서 \( q_0 \)는 시작 상태이고, 모든 \( i \)에 대해 \( q_i \to q_{i+1} \)이 전이 관계에 속합니다. 어떤 실행에 등장하는 상태 \( q \)를 도달 가능한 상태(reachable state)라고 합니다.

그래프로 그리면 직관이 확 살아나요. 각 상태를 노드로, 전이를 화살표로 표현하면 상태 기계는 방향 그래프가 됩니다. 시작 상태를 진하게 표시하고, 거기서부터 화살표를 따라 갈 수 있는 모든 노드들이 도달 가능한 상태들의 집합이지요.

예제 6.1.3 (간단한 카운터)

0부터 시작해서 매 단계 1씩 올라가는 카운터를 생각합시다. \( Q = \mathbb{N} \), \( q_0 = 0 \), \( \delta = \{ (n, n+1) : n \in \mathbb{N} \} \). 도달 가능한 상태는 \( \{0, 1, 2, \ldots\} = \mathbb{N} \) 전체입니다. 이 기계의 실행은 단 하나, \( 0 \to 1 \to 2 \to \cdots \)뿐이지요.

예제 6.1.4 (충돌 감지 카운터)

이번에는 두 사람이 같은 변수에 1을 더하려는 상황을 모델링해봐요. 상태는 정수 \( n \). 전이는 \( n \to n+1 \) 하나뿐인데, 두 프로세스가 동시에 \( n \)을 읽고 각각 \( n+1 \)을 쓰면 두 번의 증가가 한 번의 증가처럼 보일 수 있습니다. 이런 동시성 버그를 상태 기계로 정밀하게 묘사할 수 있다는 점이 포인트예요.

프로그램을 상태 기계로 보는 시각의 강력함은, "변수들의 현재 값"이라는 추상적 개념을 "상태"라는 수학적 대상으로 끌어올린다는 데 있습니다. 일단 이렇게 모델링하고 나면, 우리는 프로그램의 실행을 그래프 위의 산책으로 바꿔 분석할 수 있어요.

6.2 불변량 원리 The Invariant Principle

상태 기계가 만들 수 있는 도달 가능한 상태들의 집합은 보통 어마어마하게 큽니다. 모든 상태를 일일이 검사해서 "이 시스템은 절대 나쁜 상태에 빠지지 않는다"고 말할 수는 없죠. 그러면 어떻게 해야 할까요? 답은 5장에서 배운 귀납을 한 번 더 변주하는 데 있습니다. 바로 불변량(invariant)이라는 아이디어예요.

정의 6.2.1 (보존되는 성질)

상태 \( q \)에 대한 성질 \( P(q) \)가 상태 기계 \( M \)에서 보존된다(preserved)는 것은 다음을 의미합니다.

\[ \forall q, q' \in Q \,:\; \big(P(q) \,\wedge\, q \to q'\big) \;\Rightarrow\; P(q'). \]

즉, \( P \)가 성립하는 어떤 상태에서 한 걸음을 가면, 도착한 상태에서도 \( P \)가 여전히 성립한다는 뜻이에요.

정리 6.2.2 (불변량 원리)

성질 \( P \)가 시작 상태에서 성립하고(\( P(q_0) \)이 참), 모든 전이에 대해 보존된다면, \( P \)는 도달 가능한 모든 상태에서 성립합니다.

증명

임의의 도달 가능한 상태 \( q \)를 잡으면, 정의에 의해 어떤 실행 \( q_0 \to q_1 \to \cdots \to q_n = q \)가 존재합니다. 실행의 단계 수 \( n \)에 대해 귀납을 합시다. \( n = 0 \)이면 \( q = q_0 \)이고 가정에 의해 \( P(q_0) \)이 참. \( P(q_k) \)가 참이라 하면, \( q_k \to q_{k+1} \)이고 \( P \)가 보존되므로 \( P(q_{k+1}) \)도 참입니다. 따라서 \( P(q_n) = P(q) \)가 성립.

형식만 보면 5장의 수학적 귀납과 거의 똑같죠? "기저: 시작 상태에서 성립한다", "귀납 단계: 한 걸음 가도 보존된다." 차이는 자연수 위가 아니라 상태 기계의 실행 위에서 귀납을 한다는 점뿐이에요. 그래서 불변량 원리를 실행 귀납(induction on executions)이라고도 부릅니다.

예제 6.2.3 (6×6 보드의 X)

6×6 격자판이 있고, 왼쪽 위 칸에 X 마커가 한 개 놓여 있어요. 한 번의 동작은 X를 한 칸 위, 아래, 왼쪽, 오른쪽 중 한 방향으로 옮기는 것입니다. 질문: 적당히 옮기다 보면 X를 오른쪽 아래 칸으로 보낼 수 있을까요?

답은 "할 수 있습니다"인데, 살짝 변형해 봐요. 만약 매번 X를 옮길 때마다 그 자리에 도장을 찍어서 같은 칸을 두 번 밟지 못한다면? 또는 정확히 35번 움직여서 도착해야 한다면? 이런 문제는 칸을 체스판처럼 흑백으로 칠해 놓고 보면 답이 보입니다.

색깔 불변량: 왼쪽 위를 흰색, 그 옆을 검은색으로 칠하는 식으로 시계판 무늬를 그리면, 한 번 움직일 때마다 X가 놓인 칸의 색은 반드시 바뀝니다. 즉 "X가 놓인 칸의 색깔과 지금까지 움직인 횟수의 홀짝은 항상 같다"는 성질이 보존돼요. 시작 칸이 흰색이고 0번 움직였으면 둘 다 짝수. 35번 움직이면 홀수가 되어 X는 검은 칸에 있어야 합니다. 그런데 오른쪽 아래 칸은? 6+6이 짝수이므로 시작 칸과 같은 색, 즉 흰색이에요. 검은색이 아닙니다. 따라서 정확히 35번 만에 도달하는 것은 불가능합니다.

이 예제의 매력은, 무한히 많은 가능한 경로를 일일이 따져보지 않고도 단 한 줄의 색깔 불변량으로 결론을 내렸다는 점이에요. 좋은 불변량을 찾는 것이 곧 좋은 증명을 찾는 것입니다.

노트

불변량은 너무 약하면 도움이 안 되고, 너무 강하면 보존되지 않아요. "그럴듯해 보이지만 보존되지 않는 성질"을 강화해서 "더 풍성하지만 진짜로 보존되는 성질"로 바꾸는 작업을 불변량 강화(strengthening the invariant)라고 부릅니다. 알고리즘 분석에서 가장 많은 시간이 들어가는 부분이지요.

6.3 부분 정확성과 종료 Partial Correctness and Termination

알고리즘이 "옳다"는 말에는 사실 두 가지 약속이 들어 있습니다. 첫째, 끝날 때 답이 맞아야 한다(부분 정확성, partial correctness). 둘째, 무한히 돌지 않고 언젠가는 끝나야 한다(종료성, termination). 둘은 별개의 문제예요. 영원히 도는 알고리즘은 답을 절대 틀리지 않을 수 있고(왜냐하면 답을 절대 안 내놓으니까), 빨리 끝나는 알고리즘이 엉뚱한 답을 줄 수도 있죠. 그래서 두 가지를 따로 증명합니다.

정의 6.3.1 (부분 정확성과 종료성)

알고리즘을 상태 기계로 모델링했을 때, 종료 상태에 도달했다면 항상 올바른 답이 나오는 성질을 부분 정확성이라 합니다. 어떤 입력에서 출발하든 유한 번의 전이 안에 종료 상태에 도달하는 성질을 종료성이라 합니다. 둘이 모두 성립하면 알고리즘이 전체적으로 정확하다(totally correct)고 말합니다.

부분 정확성은 6.2의 불변량 원리로 증명합니다. "지금까지 계산한 값과 입력 사이에 어떤 관계가 항상 성립한다"는 불변량을 잡고, 이 불변량이 종료 상태에서 정답을 함의하도록 만들면 끝이에요. 종료성은 새 도구가 필요한데, 이름은 variant입니다.

정의 6.3.2 (variant)

상태 기계 \( M \)에 대해 variant는 함수 \( v : Q \to \mathbb{N} \)으로, 모든 비종료 상태 \( q \)와 그 다음 상태 \( q' \)에 대해

\[ v(q') < v(q) \]

를 만족하는 함수입니다. 즉 한 걸음을 갈 때마다 \( v \) 값이 자연수에서 엄격히 감소해요.

정리 6.3.3 (종료 정리)

상태 기계가 자연수 값을 갖는 variant를 가지면, 모든 실행은 유한 단계 안에 종료 상태에 도달합니다.

증명

variant 값은 자연수이므로 음이 될 수 없고, 매 전이마다 엄격히 줄어듭니다. 자연수의 정렬성(well-ordering principle, 5장 참고)에 의해 무한히 줄어드는 자연수 수열은 존재하지 않으므로, 어느 순간 더 이상 전이가 불가능한 상태, 즉 종료 상태에 도달합니다.

예제 6.3.4 (빠른 거듭제곱)

밑 \( a \), 지수 \( n \)에 대해 \( a^n \)을 계산하는 알고리즘을 봅시다.

def fast_pow(a, n):
    r = 1
    x = a
    k = n
    while k > 0:
        if k % 2 == 1:
            r = r * x
        x = x * x
        k = k // 2
    return r

상태는 변수 \( (r, x, k) \)의 값. 시작 상태는 \( (1, a, n) \), 종료 상태는 \( k = 0 \)인 상태.

불변량: \( r \cdot x^k = a^n \). 시작 상태에서 \( 1 \cdot a^n = a^n \)이므로 성립. 한 걸음에서 두 경우를 따져봐요. \( k \)가 홀수인 분기에서는 \( r' = r x \), \( x' = x^2 \), \( k' = (k-1)/2 \). 그러면 \( r' (x')^{k'} = r x \cdot x^{k-1} = r x^k = a^n \). 짝수 분기에서는 \( r' = r \), \( x' = x^2 \), \( k' = k/2 \)이고 \( r' (x')^{k'} = r \cdot x^k = a^n \). 양쪽 모두 보존됩니다.

variant: \( v(r, x, k) = k \). 매 반복에서 \( k \)는 \( (k-1)/2 \) 또는 \( k/2 \)로 줄어들고, 둘 다 \( k \geq 1 \)일 때 엄격히 작아집니다.

종료 시 \( k = 0 \)이므로 불변량은 \( r \cdot x^0 = r = a^n \). 즉 반환값 \( r \)이 정확히 \( a^n \). 부분 정확성과 종료성 모두 한 줄짜리 불변량과 한 줄짜리 variant로 증명됐어요.

예제 6.3.5 (유클리드 알고리즘)

두 양의 정수 \( a, b \)의 최대공약수를 구하는 고전 알고리즘.

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

상태는 \( (a, b) \). 시작 상태는 입력 \( (a_0, b_0) \), 종료는 \( b = 0 \).

불변량: \( \gcd(a, b) = \gcd(a_0, b_0) \). 임의의 \( a, b \)에 대해 \( \gcd(a, b) = \gcd(b, a \bmod b) \)는 잘 알려진 사실이므로 한 걸음마다 보존됩니다.

variant: \( v(a, b) = b \). \( b > 0 \)인 동안 \( a \bmod b < b \)이므로 새 \( b \) 값은 항상 더 작은 자연수입니다.

종료 시 \( b = 0 \)이므로 \( \gcd(a, 0) = a \). 불변량에 의해 이 값이 \( \gcd(a_0, b_0) \)와 같음. 끝!

이 두 예제에서 강조하고 싶은 건, "복잡한 코드를 한 줄씩 따라가며 머리로 시뮬레이션"하지 않는다는 점이에요. 우리는 한 줄짜리 수학적 성질 두 개(invariant + variant)를 잡고 그게 보존되는지만 검사했습니다. 코드가 길어져도 같은 원칙이 그대로 작동하는 게 이 방법의 위력입니다.

노트

variant가 꼭 자연수일 필요는 없어요. 임의의 정렬 집합(well-ordered set), 예를 들어 사전식 순서를 갖는 \( \mathbb{N} \times \mathbb{N} \) 같은 곳에서 값이 줄어들기만 해도 종료 정리가 성립합니다. 하지만 자연수가 가장 자주 쓰이고 가장 직관적이에요.

6.4 안정 결혼 문제 The Stable Marriage Problem

이제 지금까지 배운 도구를 진짜 알고리즘에 적용해 봅시다. 무대는 다소 낭만적이지만 정작 수학은 차갑고 정확해요. \( n \)명의 남자와 \( n \)명의 여자가 있고, 각자가 모든 이성을 자기 마음대로 1등부터 \( n \)등까지 줄을 세워 둔 선호 순위를 갖고 있습니다. 우리의 임무는 \( n \)쌍의 결혼을 짝지어 주는 것. 단, 결과가 "안정적"이어야 해요. 어떤 의미에서?

정의 6.4.1 (안정 매칭)

매칭 \( M \)이 두 사람 \( B \)(남자)와 \( G \)(여자)에 대해 다음을 모두 만족할 때, \( (B, G) \)를 도주 쌍(rogue couple)이라 합니다.

(1) \( M \)에서 \( B \)는 \( G \)가 아닌 다른 여자와 짝지어졌다.
(2) 그럼에도 \( B \)는 자신의 현재 짝보다 \( G \)를 더 선호한다.
(3) 동시에 \( G \)도 자신의 현재 짝보다 \( B \)를 더 선호한다.

도주 쌍이 단 한 쌍도 존재하지 않는 매칭을 안정(stable)하다고 합니다.

도주 쌍이 있다는 건 두 사람이 동시에 "지금 내 짝보다 너랑이 낫겠다"고 생각한다는 뜻이에요. 그러면 이 둘은 각자의 현재 짝을 버리고 서로에게 도망갈 동기가 충분합니다. 안정 매칭이란 그런 일이 절대 일어나지 않는 매칭이지요. 인기 비유로 말하면 아무도 환승 결혼을 시도할 이유가 없는 상태예요.

두 가지 자연스러운 질문이 떠오릅니다. (1) 어떤 선호 순위가 주어지든 안정 매칭이 항상 존재할까? (2) 존재한다면, 효율적으로 찾을 수 있을까? 둘 다 답은 "예"이고, 그 답을 동시에 주는 것이 1962년 게일과 섀플리(Gale & Shapley)의 알고리즘입니다.

정의 6.4.2 (Gale-Shapley 알고리즘)

이 알고리즘은 매일 아침 한 라운드씩 진행됩니다.

아침: 아직 결혼 약속이 확정되지 않은 모든 남자는 자기 선호 순위에서 아직 거절당하지 않은 여자 중 가장 위에 있는 사람에게 가서 청혼합니다.

점심: 청혼을 받은 여자는, 만약 청혼자가 한 명이면 그 사람을 일단 "보류"(maybe)로 잡아 두고, 여러 명이면 그중 자기 선호 순위에서 가장 높은 사람만 보류로 잡습니다. 이미 어제부터 보류 중이던 사람이 있는데 새 청혼자가 그 사람보다 자기 마음에 더 들면, 어제 보류는 풀고 새 사람으로 갈아탑니다.

저녁: 보류로 선택받지 못한 모든 청혼자는 거절당했다고 기록하고 다음 날 다른 사람에게 청혼할 준비를 합니다.

아침에 청혼할 사람이 아무도 없는 날이 오면 알고리즘은 멈추고, 모든 보류 관계가 결혼으로 확정됩니다.

약간 일방적이고 구식인 설정이지만(실제로 게일·섀플리가 1962년에 쓴 그대로의 비유입니다), 알고리즘의 수학적 성질을 분석하기에는 깔끔해요. 우선 진짜로 끝나긴 하는지부터 확인합시다.

정리 6.4.3 (종료성)

Gale-Shapley 알고리즘은 최대 \( n^2 \)일 안에 종료합니다.

증명

variant로 "거절 횟수의 총합"을 잡습니다. 정확히는, 각 남자마다 그가 아직 청혼해 보지 않은(거절당하지도 않은) 여자의 수를 합한 값을 \( v \)라 합시다. 처음에는 \( v = n \cdot n = n^2 \). 매 라운드에서 적어도 한 명의 남자가 거절당하지 않으면(즉 모두가 보류 상태가 되면) 알고리즘은 끝나고, 한 명이라도 거절당하면 그 사람의 "후보 목록"에서 한 명이 빠지므로 \( v \)는 적어도 1 감소합니다. \( v \)는 자연수이므로 \( n^2 \)번 이내에 0 또는 종료에 도달합니다.

다음으로, 끝났을 때 진짜로 모두가 짝지어지는지를 확인해야 합니다.

보조정리 6.4.4 (보류의 단조성)

일단 어떤 여자가 누군가를 보류로 잡으면, 그 이후로 그녀의 보류 상대는 점점 자기 선호 순위에서 위로 올라가기만 합니다(절대 내려가지 않아요).

이건 알고리즘 정의에서 바로 따라옵니다. 새 청혼자로 갈아탈 때는 무조건 더 마음에 드는 쪽으로만 갈아타니까요. 이 단조성에서 또 하나가 따라 나옵니다.

보조정리 6.4.5 (모두 짝지어진다)

알고리즘이 끝났을 때, 모든 사람은 정확히 한 명의 짝을 갖습니다.

증명

모순으로 가정합시다. 종료 시 짝이 없는 남자 \( B \)가 있다고 해요. 그러면 \( B \)는 \( n \)명의 여자 모두에게 한 번씩 거절당했어야 알고리즘이 종료했을 것입니다(아니면 그는 아직 청혼할 사람이 남아 있어서 종료하지 않을 테니까). 그런데 보조정리 6.4.4에 의해, 한 번이라도 보류를 잡아본 여자는 종료 시점까지 계속 누군가를 보류로 잡고 있어요. 그리고 모든 여자는 \( B \)에게 청혼받은 적이 있으니 모두 한 번 이상 보류 상태였습니다. 따라서 \( n \)명의 여자가 모두 짝을 갖고 있는데, 짝지어진 여자의 수가 \( n \)이면 짝지어진 남자의 수도 \( n \). 그런데 \( B \)는 짝이 없다고 했으니 모순.

이제 가장 중요한 안정성을 증명할 차례예요. 핵심 아이디어는 매혹적일 만큼 단순합니다.

정리 6.4.6 (안정성)

Gale-Shapley 알고리즘이 만들어 내는 매칭은 안정적입니다. 즉 도주 쌍이 존재하지 않습니다.

증명

모순으로 도주 쌍 \( (B, G) \)가 있다고 가정합시다. \( B \)의 짝은 \( G' \neq G \)이고 \( G \)의 짝은 \( B' \neq B \)인데, \( B \)는 \( G \)를 \( G' \)보다 선호하고, \( G \)는 \( B \)를 \( B' \)보다 선호한다고 하지요.

\( B \)는 알고리즘 동안 자기 선호 순위의 위에서부터 청혼합니다. \( B \)에게 \( G \)는 \( G' \)보다 위에 있으므로, \( B \)는 \( G' \)에게 청혼하기 전에 반드시 \( G \)에게 먼저 청혼했을 것입니다. 그런데 \( G \)는 결국 다른 사람 \( B' \)와 짝지어졌어요. 두 가지 가능성이 있습니다. (a) \( G \)가 \( B \)의 청혼을 거절했거나, (b) 잠깐 보류했다가 나중에 다른 사람으로 갈아탔거나. 둘 다 결국 \( G \)는 \( B \)를 버린 것이고, 그건 \( G \)가 그 시점에 더 마음에 드는 다른 청혼자가 있었다는 뜻입니다.

이제 보조정리 6.4.4(보류의 단조성)가 결정타예요. \( G \)가 \( B \)를 버리고 잡은 누군가는 \( B \)보다 위에 있고, 그 후로 \( G \)의 보류 상대는 계속 위로만 올라갔습니다. 따라서 종료 시점의 짝 \( B' \)도 \( B \)보다 위에 있어요. 즉 \( G \)는 \( B' \)를 \( B \)보다 더 선호합니다. 그런데 우리는 \( G \)가 \( B \)를 \( B' \)보다 선호한다고 가정했지요. 모순.

그림으로 정리하면 이래요. \( B \)는 자기 선호 순위의 꼭대기에서부터 차례로 청혼하니까 \( G' \)와 짝이 됐다는 건 \( G \)에게 이미 거절당한 적이 있다는 증거고, 거절당했다는 건 \( G \)에게 그때 더 좋은 사람이 있었다는 증거고, 보류는 단조 증가하니까 종료 시점에는 더 좋아졌으면 좋아졌지 나빠질 수 없다. 한마디로 청혼하는 쪽이 위에서 아래로 내려간다는 사실과, 받는 쪽이 받은 사람들 사이에서 위로 올라간다는 사실이 만나는 지점에서 도주 쌍은 살 자리가 없습니다.

안정성과 종료성에 더해, Gale-Shapley 알고리즘에는 한 가지 흥미로운 성질이 더 있어요.

정리 6.4.7 (청혼자 최적성)

Gale-Shapley 알고리즘이 출력하는 매칭은 청혼자(남자) 입장에서 최적입니다. 즉 모든 남자에 대해, 그 남자가 어떤 안정 매칭에서든 가질 수 있는 가장 선호하는 짝과 짝지어집니다.

증명의 핵심 아이디어만 짚을게요. 어떤 남자 \( B \)가 자기의 "이론상 가능한 최고 짝" \( G \)를 못 받았다고 가정해 봅시다. 즉 알고리즘 진행 중 \( G \)가 \( B \)를 거절하는 첫 번째 순간이 있어요. 그 순간 \( G \)는 \( B \)보다 더 좋은 누군가 \( B^* \)를 보류로 잡고 있었던 거고, 그러면 \( B^* \)도 그 시점까지 자기 선호 순위 위쪽에서 거절당하지 않은 채 \( G \)에게 도달한 거예요. 이 \( B^* \)에게도 \( G \)가 안정 매칭 가능한 짝이라는 가정을 풀어 보면, \( B^* \)의 "이론상 가능한 최고 짝"보다 \( G \)가 위에 있다는 결론이 나오고, 그것을 안정 매칭의 정의와 결합하면 도주 쌍이 만들어져 모순. 즉 "거절당하는 첫 번째 남자"가 존재할 수 없습니다.

노트

대칭적으로 같은 알고리즘은 받는 쪽(여자) 입장에서는 최악입니다. 모든 여자가 어떤 안정 매칭에서든 받을 수 있는 가장 안 좋은 짝을 받게 돼요. 그래서 현실의 매칭 시장(예: 의대 졸업생-병원 배정)에서는 누가 청혼하는 역할을 맡느냐가 매우 중요한 정치적 문제가 됩니다. 게일과 섀플리 그리고 후속 연구로 알 로스(Al Roth)는 이 알고리즘의 변형으로 노벨 경제학상을 받았어요. 사랑 이야기로 시작해서 시장 설계로 끝나는 셈이지요.

이 챕터를 한 줄로 요약하면 이렇게 됩니다. 프로그램은 상태 기계, 옳음의 증명은 불변량, 끝남의 증명은 variant. 도구는 단순하지만 적용 범위는 넓어요. 그리고 그 도구의 뿌리는 결국 5장의 귀납이라는 한 가지 원리입니다. 다음 챕터로 가면 이 도구들이 더 큰 구조 — 그래프와 그 위의 알고리즘 — 에서 어떻게 쓰이는지 보게 될 거예요.

PART I — 증명

7 재귀적 데이터 타입 Recursive Data Types

"리스트는 빈 리스트이거나 (원소, 리스트)다." 단 한 줄짜리 이 문장이 사실 모든 자료구조의 어머니예요. 이 챕터에서는 자기 자신을 다시 부르는 방식으로 정의된 집합 — 재귀적 데이터 타입 — 을 살펴보고, 그 위에서 함수를 정의하고 성질을 증명하는 도구인 구조적 귀납법을 배웁니다. 자연수 위의 수학적 귀납법이 "더 일반적인 모양"으로 변신하는 순간이라고 보면 됩니다.

7.1 재귀 정의와 구조적 귀납 Recursive Definitions and Structural Induction

어떤 집합을 정의할 때, 원소 하나하나를 일일이 나열하기보다 "재료 + 조립 규칙"으로 묘사하면 훨씬 깔끔합니다. 자연수 \( \mathbb{N} \) 을 떠올려 보세요. \( 0 \in \mathbb{N} \) 이고, \( n \in \mathbb{N} \) 이면 \( n+1 \in \mathbb{N} \) 이다. 이 두 줄이면 무한히 많은 자연수를 모두 길어 올릴 수 있어요. 이게 재귀 정의의 본질입니다.

정의 7.1.1 (재귀적으로 정의된 집합)

집합 \( R \) 의 재귀적 정의는 두 부분으로 이루어집니다.

(1) 기저 (base case): \( R \) 의 어떤 원소들이 처음부터 존재한다고 선언.
(2) 구성자 (constructor): \( R \) 의 원소로부터 새로운 원소를 만드는 규칙들.
그리고 \( R \) 은 위 규칙으로 만들어지는 가장 작은 집합으로 정합니다.

"가장 작은 집합"이라는 마지막 조건이 핵심이에요. 이게 없으면 별난 원소를 끼워 넣어도 정의를 만족할 수 있거든요. 이 조건 덕분에 \( R \) 의 모든 원소는 기저에서 시작해서 구성자를 유한 번 적용한 결과로 얻어집니다.

원리 7.1.2 (구조적 귀납법)

\( R \) 이 재귀 정의된 집합이라 하자. 어떤 술어 \( P \) 에 대해

(i) 모든 기저 원소 \( b \in R \) 에서 \( P(b) \) 가 성립하고,
(ii) 임의의 구성자 \( c \) 와 그 입력 \( x_1, \dots, x_k \in R \) 에 대해 \( P(x_1) \wedge \dots \wedge P(x_k) \implies P(c(x_1, \dots, x_k)) \)

가 모두 성립하면, \( \forall x \in R : P(x) \) 이다.

자연수의 귀납법은 기저 \( \{0\} \) 에 구성자 \( n \mapsto n+1 \) 하나뿐인 특수 사례예요. 구조적 귀납은 기저와 구성자가 더 풍부할 뿐, 같은 정신입니다. 재귀로 정의된 집합 위에서 함수를 정의할 때도 같은 틀을 씁니다 — 기저 원소에서 값을 정하고, 구성자에는 "입력값에서 출력값을 만드는 규칙"을 적어 두면 끝.

7.2 균형 괄호 문자열 Strings of Matched Brackets

이제 구체적인 예로 들어가 봅시다. 알파벳 \( \{ \, [\,, \,] \, \} \) 위의 문자열 중에서 "괄호가 잘 짝지어진" 것들의 모임 \( \mathrm{RecMatch} \) 를 정의하고 싶어요. 직관적으로는 [][[]] 같은 건 OK, ][ 같은 건 NO.

정의 7.2.1 (RecMatch)

집합 \( \mathrm{RecMatch} \) 를 다음과 같이 정합니다.

(기저) 빈 문자열 \( \lambda \in \mathrm{RecMatch} \).
(구성자) \( s, t \in \mathrm{RecMatch} \) 이면 \( [\,s\,]\,t \in \mathrm{RecMatch} \).

예를 들어 \( s = t = \lambda \) 면 \( [\,]\, \lambda = [] \) 가 만들어지고, 거기서 다시 \( [\, []\, ] \, [] = [[]][] \) 같은 문자열이 자라납니다. 이 정의 한 줄로 무한히 많은 균형 문자열이 모두 나오는 게 신기해요.

그런데 같은 집합을 다르게 정의할 수도 있습니다. 다른 책에서는 다음 정의를 만나곤 해요.

정의 7.2.2 (AltMatch)

(기저) \( \lambda \in \mathrm{AltMatch} \).
(구성자 1) \( s \in \mathrm{AltMatch} \) 이면 \( [\,s\,] \in \mathrm{AltMatch} \).
(구성자 2) \( s, t \in \mathrm{AltMatch} \) 이면 \( s\,t \in \mathrm{AltMatch} \).

정리 7.2.3

\( \mathrm{RecMatch} = \mathrm{AltMatch} \).

증명 (스케치)

양방향 포함을 각각 구조적 귀납으로 보입니다. \( \mathrm{RecMatch} \subseteq \mathrm{AltMatch} \) 방향: \( \lambda \in \mathrm{AltMatch} \) 는 기저로 OK. \( s, t \in \mathrm{AltMatch} \) 라 가정하면 구성자 1로 \( [s] \in \mathrm{AltMatch} \), 구성자 2로 \( [s]\,t \in \mathrm{AltMatch} \).

반대 방향도 비슷합니다. \( [s] = [s]\,\lambda \) 와 \( s\,t \) 를 RecMatch 안에서 차곡차곡 만들어 주면 됩니다 (조금 더 손이 가요).

"정의가 다른데 같은 집합"이라는 건 모델링에서 흔히 쓰는 트릭이에요. 어떤 정의는 증명에 편하고, 어떤 정의는 알고리즘에 편하니까 상황에 따라 골라 쓸 수 있게 둘이 같다는 사실을 챙겨 두는 거죠.

7.3 비음 정수 위 재귀 함수 Recursive Functions on Nonnegative Integers

\( \mathbb{N} \) 자체가 재귀 데이터 타입이니, 그 위에서 정의되는 함수들도 자연스레 재귀로 적습니다. 가장 단순한 친구는 팩토리얼.

정의 7.3.1 (팩토리얼)

\( 0! = 1 \), \( (n+1)! = (n+1) \cdot n! \).

두 번째 줄에 우변에 \( n! \) 이 다시 등장하는 게 재귀의 핵심이에요. "다음 값"을 "이전 값"으로 표현합니다. 피보나치 수열은 직전 두 값을 모두 참조하는 점만 다를 뿐 같은 패턴.

정의 7.3.2 (피보나치)

\( F(0) = 0,\ F(1) = 1,\ F(n+2) = F(n+1) + F(n) \).

여기서 한 발 더 나가면 아커만 함수가 기다립니다. 정말 묘한 친구예요.

정의 7.3.3 (아커만 함수)

\[ A(0, n) = n+1, \quad A(m+1, 0) = A(m, 1), \quad A(m+1, n+1) = A(m,\, A(m+1, n)). \]

손으로 \( A(2, 2) \) 정도까지 펼쳐 보면 금방 \( A(2,2) = 7 \) 이 나오지만, \( A(4, 2) \) 는 우주 원자 수보다 큰 값입니다. 더 무서운 건 이 함수가 "원시 재귀(primitive recursive)" 의 틀로는 절대 표현되지 않는다는 사실이에요. 즉, 단순 for-loop의 합성으로는 흉내 낼 수 없는, "진짜 재귀"가 필요한 함수의 대표주자입니다.

노트 (잘 정의됨에 대해)

재귀 정의가 정말 함수 하나를 결정하려면, 모든 입력에서 종료해야 해요. 팩토리얼/피보나치/아커만은 둘째 인자(또는 인자 자체)가 매번 작아지는 식으로 종료가 보장됩니다. \( f(n) = f(n)+1 \) 같은 정의는 절대 함수가 안 됩니다 — 자기 자신을 깎지 못하니까요.

7.4 산술식 Arithmetic Expressions

"(3 + 4) * 5" 같은 산술식을 컴퓨터가 어떻게 다루는지 들여다봅시다. 문자열로 보면 골치 아프지만, 재귀 데이터 타입으로 보면 단정해요.

정의 7.4.1 (산술식 \( \mathrm{Aexp} \))

(기저) 모든 정수 상수 \( c \) 와 변수 \( x \) 는 \( \mathrm{Aexp} \) 의 원소.
(구성자) \( e_1, e_2 \in \mathrm{Aexp} \) 이고 \( \star \in \{+, -, \times\} \) 이면 \( (e_1 \star e_2) \in \mathrm{Aexp} \).

이 정의가 실제로 만들어내는 건 우리가 컴파일러 강의에서 보는 추상 구문 트리(AST)예요. 잎(leaf)은 상수와 변수, 내부 노드는 연산자. 식 위의 함수 \( \mathrm{eval}(e, \sigma) \) — 변수 환경 \( \sigma \) 아래에서 식의 값을 매기는 — 도 재귀로 깔끔하게 적힙니다.

정의 7.4.2 (eval)

\( \mathrm{eval}(c, \sigma) = c \), \( \mathrm{eval}(x, \sigma) = \sigma(x) \), \( \mathrm{eval}((e_1 \star e_2), \sigma) = \mathrm{eval}(e_1, \sigma) \star \mathrm{eval}(e_2, \sigma) \).

트리에 대해 자주 묻는 두 양은 깊이 \( d(e) \) 와 크기 \( s(e) \) 입니다. 각각도 재귀로: \( d(c) = d(x) = 0 \), \( d((e_1 \star e_2)) = 1 + \max(d(e_1), d(e_2)) \); \( s(c) = s(x) = 1 \), \( s((e_1 \star e_2)) = 1 + s(e_1) + s(e_2) \).

예제 7.4.3

\( e = ((x + 3) \times (x - 1)) \). 그러면 \( d(e) = 2 \), \( s(e) = 5 \). \( \sigma(x) = 4 \) 라면 \( \mathrm{eval}(e, \sigma) = (4+3) \times (4-1) = 21 \).

구조적 귀납을 적용하면 "이진트리에서 \( s(e) \le 2^{d(e)+1} - 1 \)" 같은 사실을 깔끔히 증명할 수 있어요. AST에서 함수형 인터프리터, 그리고 컴파일러 최적화의 정확성 증명까지 — 모두 이 작은 재귀 정의에서 출발합니다.

7.5 재귀 데이터로 본 게임 Games as a Recursive Data Type

체스나 틱택토 같은 두 사람 결정 게임도 사실은 재귀 데이터 타입의 한 사례예요. "게임 상태"는 곧 그 상태에서 가능한 다음 상태들의 리스트이고, 이게 끝나는 지점은 "승/패/무"가 결정된 단말 상태.

정의 7.5.1 (게임 트리)

게임 트리 \( G \) 는 다음과 같이 정의된 자료입니다.

(기저) 단말 상태 — \( \{\text{승}, \text{패}, \text{무}\} \) 중 하나의 결과를 가짐.
(구성자) 한 플레이어가 행동할 차례인 내부 노드는, 가능한 행동에 따른 자식 게임 트리들의 모임 \( G_1, \dots, G_k \) 로 만들어짐.

이 위에서 미니맥스 값이 재귀로 정의돼요. 내가 둘 차례면 자식 값들의 \( \max \), 상대가 둘 차례면 \( \min \). 잎에서는 결과 그 자체.

정리 7.5.2 (체르멜로의 정리)

유한한 두 사람 완전정보 결정 게임에서는, 둘 중 한 명에게 필승 전략이 있거나 양쪽 모두 무승부 이상을 보장하는 전략을 가집니다.

증명 (한 줄 스케치)

게임 트리 위에서 구조적 귀납. 단말 노드는 결과가 정해져 있으니 자명. 내부 노드에서는 자식 노드들에 귀납 가정을 적용해 미니맥스 값을 계산하면 그게 그 노드에서의 최선의 보장값. 트리가 유한하니 절차가 끝납니다.

이 정리 덕분에 체스도 "이론적으론 결정 게임"이라는 표현이 가능합니다. 다만 트리가 너무 커서 우리가 모를 뿐이에요. 재귀 정의 + 구조적 귀납이 추상적인 존재성 증명을 얼마나 가볍게 해주는지 보여주는 멋진 예입니다.

7.6 검색 트리 Search Trees

자료구조 강의의 단골인 이진 검색 트리(BST)도 재귀로 정의해 두면 정리/삽입/검색 알고리즘을 매끈하게 다룰 수 있어요.

정의 7.6.1 (BST)

(기저) 빈 트리 \( \mathrm{Nil} \) 은 BST.
(구성자) 키 \( k \), 좌측 BST \( L \), 우측 BST \( R \) 이 있고 \( L \) 의 모든 키 \( < k < \) \( R \) 의 모든 키이면 \( \mathrm{Node}(k, L, R) \) 도 BST.

검색은 한 줄로 적힙니다.

def find(t, x):
    if t is Nil: return False
    if x < t.key: return find(t.left, x)
    if x > t.key: return find(t.right, x)
    return True

삽입도 같은 흐름. 빈 자리를 찾을 때까지 한쪽으로 내려가서 새 노드를 매답니다.

정리 7.6.2 (find의 정확성)

\( \mathrm{find}(t, x) \) 는 \( x \) 가 \( t \) 의 어떤 노드의 키인 경우 정확히 그 경우에만 \( \mathrm{True} \) 를 반환한다.

증명 (스케치)

BST 정의에 대한 구조적 귀납. 기저: \( t = \mathrm{Nil} \) 이면 키가 없으니 \( \mathrm{False} \) 가 맞음. 귀납: \( t = \mathrm{Node}(k, L, R) \) 에서 \( x < k \) 면 BST 조건상 \( x \) 는 \( R \) 에 있을 수 없으므로 \( L \) 만 보면 충분. 반대 경우도 대칭. \( x = k \) 면 그대로 발견.

"BST 조건"이라는 작은 불변량 하나가 알고리즘의 정확성을 통째로 보장한다는 점에 주목하세요. 재귀 데이터 타입의 정의 안에 알고리즘 분석의 핵심이 미리 들어가 있는 셈입니다.

7.7 컴퓨터과학에서의 귀납 Induction in Computer Science

마지막으로 한 발 물러서서 큰 그림을 봅시다. 알고리즘이 정확함을 증명하려고 할 때, 우리는 거의 항상 어떤 형태의 귀납을 씁니다.

  • 반복문의 정확성은 루프 불변량을 자연수에 대한 귀납으로 증명.
  • 재귀 함수의 정확성은 입력 크기 또는 입력의 구조에 대한 구조적 귀납으로.
  • 컴파일러/타입시스템의 안정성(soundness)은 프로그램의 추상 구문 트리에 대한 구조적 귀납으로.
  • 그래프/트리 알고리즘은 보통 깊이 또는 정점 수에 대한 (강한) 귀납으로.

한 마디로, 자료구조가 재귀로 정의되어 있다면 그 위 알고리즘의 정확성 증명은 그 정의를 그대로 따라가는 구조적 귀납이 됩니다. 자료구조 정의 → 함수 정의 → 정확성 증명, 이 세 단계가 같은 모양으로 펼쳐지는 거예요.

한 줄 정리

"재귀 데이터 타입은 정의 안에 그 자신을 다루는 방법을 이미 품고 있다." 구성자를 따라 함수를 적고, 그 구성자를 따라 증명을 적으면 됩니다. 이게 형식 검증과 함수형 프로그래밍이 닮은 이유고, 앞으로의 챕터에서 그래프/상태기계/언어를 다룰 때마다 다시 마주할 패턴입니다.

자, 자연수의 귀납이 "더 일반적인 귀납"으로 확장되는 풍경을 한 번 봤어요. 다음 챕터부터는 이 도구를 들고 무한 합, 점근 분석, 그래프 같은 더 큰 무대로 나갑니다. 도구는 같으니 겁먹지 말고 가요.

PART I — 증명

8 무한 집합 Infinite Sets

유한한 세계에서 \(|A| = |B|\)는 그냥 원소를 세서 비교하면 됩니다. 그런데 무한이 되면 "센다"는 행위 자체가 의심스러워지죠. 이 챕터에서는 무한 집합의 크기를 어떻게 비교할지 정의하고, 모든 무한이 같은 크기가 아니라는 충격적인 사실을 만나봅니다. 그리고 그 발견의 부산물로 컴퓨터과학의 가장 유명한 결과 중 하나, 정지 문제(Halting Problem)의 해결 불가능성을 증명합니다. 누군가 그랬어요. "어떤 무한이 다른 무한보다 크다는 사실에 충격받지 않으면 마음이 죽은 것이다." 다행히 우리는 살아있습니다.

8.1 무한 기수 Infinite Cardinality

유한 집합이라면 크기 비교는 쉽습니다. 사과 5개와 배 5개는 같은 개수이고, 사과 5개와 배 7개는 배가 더 많죠. 하지만 자연수 \(\mathbb{N} = \{0, 1, 2, 3, \dots\}\)와 짝수 전체 \(2\mathbb{N} = \{0, 2, 4, 6, \dots\}\)는 누가 더 많을까요?

"짝수는 자연수의 절반이니까 자연수가 두 배 많지!" — 이게 직관적인 답이지만, 무한의 세계에서는 직관이 자주 무너집니다. 19세기 칸토어(Cantor)가 제시한 답은 깔끔합니다. 두 집합 사이에 일대일 대응(전단사)이 존재하면 같은 크기다. 짝수와 자연수 사이엔 \(n \mapsto 2n\)이라는 전단사가 있으니, 두 집합은 같은 크기입니다. "전체와 일부가 같은 크기"라는 게 무한의 본질이에요.

정의 8.1.1 (집합의 크기 비교)

집합 \(A\), \(B\)에 대해:

(1) 단사 \(f : A \to B\)가 존재하면 \(|A| \le |B|\)라고 씁니다.
(2) 전단사 \(f : A \to B\)가 존재하면 \(|A| = |B|\)라고 씁니다.
(3) \(|A| \le |B|\)이면서 \(|A| = |B|\)는 아니면 \(|A| < |B|\)라고 씁니다.

유한 집합에서 이 정의는 우리가 아는 "원소 개수"와 정확히 일치합니다. 그리고 이 정의는 무한 집합으로 자연스럽게 확장돼요. 단, 직관과 충돌할 각오는 해야 합니다.

정의 8.1.2 (가산집합)

집합 \(A\)가 자연수 집합 \(\mathbb{N}\)과 같은 크기일 때, 즉 \(|A| = |\mathbb{N}|\)일 때 \(A\)를 가산무한(countably infinite)이라고 합니다. 유한이거나 가산무한이면 그냥 가산(countable)이라고 부르고, 그렇지 않으면 비가산(uncountable)입니다.

가산무한이라는 건 결국 "원소를 \(a_0, a_1, a_2, \dots\)로 줄세울 수 있다"는 뜻입니다. 자연수와 일대일 대응이라는 건 자연수 인덱스를 붙일 수 있다는 거니까요.

예제 8.1.3 (정수는 가산이다)

정수 집합 \(\mathbb{Z}\)는 음수까지 포함해서 자연수보다 두 배 큰 것 같은데, 사실 가산입니다. 다음과 같이 줄세우면 돼요:

\[ 0, \ 1, \ -1, \ 2, \ -2, \ 3, \ -3, \ \dots \]

전단사 \(f : \mathbb{N} \to \mathbb{Z}\)를 명시적으로 쓰면:

\[ f(n) = \begin{cases} n/2 & n \text{이 짝수} \\ -(n+1)/2 & n \text{이 홀수} \end{cases} \]

이걸로 \(|\mathbb{Z}| = |\mathbb{N}|\)이 증명됩니다.

예제 8.1.4 (유리수도 가산이다)

유리수 \(\mathbb{Q}\)는 정수보다 훨씬 빽빽해 보입니다. 어떤 두 유리수 사이에도 무한히 많은 유리수가 있죠. 그런데도 가산입니다. 양의 유리수 \(p/q\) (단, \(p, q > 0\))를 격자 위에 펼쳐놓고 대각선을 따라 지그재그로 줄세우면 됩니다:

1/1  1/2  1/3  1/4  ...
2/1  2/2  2/3  2/4  ...
3/1  3/2  3/3  3/4  ...
 .    .    .    .
순서: 1/1, 1/2, 2/1, 1/3, 2/2, 3/1, 1/4, 2/3, 3/2, 4/1, ...
      

중복된 분수(예: \(2/2 = 1/1\))는 건너뛰면 양의 유리수 전체에 자연수 인덱스가 매겨집니다. 음의 유리수와 0까지 끼워 넣으면 \(|\mathbb{Q}| = |\mathbb{N}|\)이 끝납니다.

여기까지 보면 "어쩌면 모든 무한이 다 같은 크기 아닌가?" 싶죠. 칸토어 본인도 한동안 그렇게 의심했다고 합니다. 그런데 1874년경 그는 충격적인 사실을 발견합니다. 실수 \(\mathbb{R}\)은 자연수와 같은 크기가 아니다. 더 큽니다.

정리 8.1.5 (칸토어, 1874)

실수 집합 \(\mathbb{R}\)은 비가산이다. 즉 \(|\mathbb{N}| < |\mathbb{R}|\).

증명 (대각선 논법)

편의를 위해 구간 \([0, 1)\)에 속하는 실수만 봐도 충분합니다. 이것이 가산이 아님을 보이면 \(\mathbb{R}\) 전체도 가산일 수 없으니까요.

모순을 위해 \([0, 1)\)이 가산이라고 가정합시다. 그러면 모든 원소를 \(r_0, r_1, r_2, \dots\)로 줄세울 수 있어요. 각 실수를 무한 소수로 표현합시다 (예를 들어 0.5는 \(0.5000\dots\)으로):

\[ \begin{aligned} r_0 &= 0.\,d_{00} d_{01} d_{02} d_{03} \dots \\ r_1 &= 0.\,d_{10} d_{11} d_{12} d_{13} \dots \\ r_2 &= 0.\,d_{20} d_{21} d_{22} d_{23} \dots \\ &\vdots \end{aligned} \]

여기서 \(d_{ij}\)는 \(r_i\)의 소수점 \(j+1\)번째 자리 숫자입니다. 이제 새로운 실수 \(x\)를 다음 규칙으로 만듭시다. \(x\)의 \(i\)번째 소수 자리를:

\[ x_i = \begin{cases} 1 & d_{ii} \neq 1 \\ 2 & d_{ii} = 1 \end{cases} \]

즉 대각선의 \(d_{ii}\)와 다른 숫자를 골라 넣습니다. 그리고 \(0\)이나 \(9\)는 일부러 피해서, "\(0.4999\dots = 0.5000\dots\)" 같은 표현 중복 문제를 차단했어요.

이제 이 \(x\)를 봅시다. \(x\)는 \([0, 1)\)에 속하는 실수입니다. 그런데 어떤 \(r_i\)와도 같지 않아요. 왜냐하면 \(x\)와 \(r_i\)는 적어도 \(i\)번째 소수 자리에서 다르거든요. 따라서 \(x\)는 우리의 목록 어디에도 등장하지 않습니다. 이는 "모든 원소를 줄세웠다"는 가정에 모순이에요. 따라서 \([0, 1)\)은 비가산이고, \(\mathbb{R}\)도 비가산입니다.

이 기법이 그 유명한 칸토어 대각선 논법(Cantor's diagonal argument)입니다. 표를 만들어놓고 대각선을 골라 그것과 다른 무언가를 만든다는 발상이에요. 이 발상은 다음 절에서 컴퓨터과학을 뒤흔들게 됩니다.

노트

가산 무한의 크기를 \(\aleph_0\) (알레프 영, aleph-null)이라고 부릅니다. 실수의 크기는 \(\mathfrak{c}\) (continuum)라 부르고, \(\aleph_0 < \mathfrak{c}\)입니다. "그 사이 크기의 집합이 있는가?"라는 질문이 그 유명한 연속체 가설(Continuum Hypothesis)인데, 8.4절에서 살짝 다시 언급합니다.

8.2 정지 문제 The Halting Problem

"이 프로그램이 무한 루프에 빠지나, 아니면 언젠가 끝나나?" — 코드를 짜본 사람이라면 누구나 떠올린 질문일 겁니다. 이걸 자동으로 판정해주는 도구가 있다면 디버깅이 얼마나 편해질까요. 컴파일러가 무한 루프를 미리 잡아주면 좋잖아요. 그런데 1936년 앨런 튜링(Alan Turing)이 결정적인 답을 줬습니다. 그런 도구는 원리적으로 만들 수 없다.

여기서 "프로그램"은 임의의 알고리즘을 의미합니다. 파이썬, C, 튜링 기계, 람다 계산 — 표현 방식이 무엇이든 상관없어요. 핵심은 다음 함수를 계산하는 알고리즘이 존재하느냐는 것입니다:

정의 8.2.1 (정지 문제)

입력 \((P, x)\) — 프로그램 \(P\)의 소스 코드와 입력 \(x\) — 를 받아 다음을 출력하는 알고리즘이 있는가?

\[ \text{Halt}(P, x) = \begin{cases} \text{true} & P \text{가 입력 } x \text{에 대해 정지} \\ \text{false} & P \text{가 입력 } x \text{에 대해 무한 루프} \end{cases} \]

"그냥 돌려보면 되지 않나?" 싶지만, 무한 루프인 경우엔 영원히 결과를 알 수 없습니다. 우리가 원하는 건 유한 시간 안에 항상 정확한 답을 내는 알고리즘이에요.

정리 8.2.2 (튜링, 1936)

정지 문제를 풀 수 있는 알고리즘은 존재하지 않는다.

증명 (대각선 논법의 컴퓨터과학판)

모순을 위해 가정합니다. \(\text{Halt}(P, x)\)를 정확히 계산하는 알고리즘이 있다고 합시다. 그러면 우리는 이걸 부품으로 써서 또 다른 프로그램 \(\text{Trouble}\)을 만들 수 있어요:

def Trouble(P):
    if Halt(P, P) == True:
        while True:
            pass        # 일부러 무한 루프
    else:
        return          # 그냥 정지

\(\text{Trouble}\)은 프로그램 \(P\)를 입력으로 받아, "\(P\)가 자기 자신을 입력으로 했을 때 정지한다면 무한 루프에 빠지고, 정지 안 한다면 정지한다." 청개구리처럼 거꾸로 행동합니다.

이제 결정적인 한 수. \(\text{Trouble}\) 자체에 \(\text{Trouble}\)을 입력으로 줘봅시다. \(\text{Trouble}(\text{Trouble})\)은 정지할까요?

  • 경우 1. \(\text{Trouble}(\text{Trouble})\)이 정지한다고 가정하자. 코드를 보면, 정지하려면 \(\text{Halt}(\text{Trouble}, \text{Trouble}) = \text{false}\)여야 합니다. 그런데 \(\text{Halt}\)의 정의상 \(\text{false}\)는 "\(\text{Trouble}\)을 \(\text{Trouble}\)에 적용했을 때 무한 루프"를 뜻해요. 모순.
  • 경우 2. \(\text{Trouble}(\text{Trouble})\)이 무한 루프라고 가정하자. 코드를 보면, 무한 루프에 빠지려면 \(\text{Halt}(\text{Trouble}, \text{Trouble}) = \text{true}\)여야 합니다. 그런데 \(\text{true}\)는 "정지"를 뜻해요. 또 모순.

두 경우 모두 모순이므로, 처음 가정 — "\(\text{Halt}\)를 계산하는 알고리즘이 있다" — 이 틀렸습니다.

이 증명은 정확히 칸토어의 대각선 논법과 같은 골격입니다. 칸토어는 "모든 실수의 목록"을 가정하고, 대각선의 \(i\)번째 자리를 뒤집어서 목록에 없는 실수를 만들었어요. 튜링은 "모든 프로그램에 대한 정지 판정"을 가정하고, "자기 자신에 대한 답"을 뒤집은 \(\text{Trouble}\)을 만들었습니다. 둘 다 "표의 대각선을 부정하면 모순"이라는 같은 패턴이에요.

노트

정지 문제의 결과는 단순히 "한 가지 문제를 못 푼다"가 아닙니다. 컴퓨터로 표현 가능한 모든 알고리즘의 한계를 보여주는 결과예요. 함수의 가짓수는 비가산인데(실수만큼 많음), 프로그램의 가짓수는 가산이거든요(유한한 문자열의 집합이니까). 그러니 대부분의 함수는 어떤 프로그램으로도 계산할 수 없습니다. 정지 문제는 그 무수히 많은 "계산 불가능한 함수" 중 하나일 뿐이에요.

실용적으로 보면 슬픈 결과지만, 한편으론 컴파일러 작성자에게 면죄부이기도 합니다. "왜 무한 루프 못 잡아줘?"에 대해 "그건 원리적으로 불가능합니다"라고 답할 수 있게 됐으니까요.

8.3 집합의 논리 The Logic of Sets

지금까지 \(|A| = |B|\)는 전단사로, \(|A| \le |B|\)는 단사로 정의했습니다. 그런데 정말 이 정의가 우리의 직관처럼 작동할까요? 예를 들어 "\(|A| \le |B|\)이고 \(|B| \le |A|\)이면 \(|A| = |B|\)다"라는 명제는 당연해 보이지만, 무한 집합에선 증명이 필요합니다. 이게 바로 슈뢰더-베른슈타인 정리예요.

정리 8.3.1 (슈뢰더-베른슈타인)

단사 \(f : A \to B\)와 단사 \(g : B \to A\)가 모두 존재하면, 전단사 \(h : A \to B\)가 존재한다. 즉 \(|A| \le |B|\)이고 \(|B| \le |A|\)이면 \(|A| = |B|\).

증명은 여기선 생략하지만, 핵심 아이디어는 이렇습니다. 각 원소의 "출신 사슬"을 거꾸로 거슬러 올라가서, 사슬이 \(A\)에서 시작했는지 \(B\)에서 시작했는지에 따라 \(f\)를 쓸지 \(g^{-1}\)을 쓸지 골라 \(h\)를 정의합니다. 손으로 그림 그려보면 의외로 깔끔해요.

이제 한 단계 더 나아가, "주어진 집합보다 더 큰 집합을 항상 만들 수 있는가?"라는 질문을 던져봅시다. 답은 그렇습니다 — 그것도 매우 자연스러운 방법으로요. 멱집합을 쓰면 됩니다.

정의 8.3.2 (멱집합)

집합 \(A\)의 멱집합(power set) \(\mathcal{P}(A)\)는 \(A\)의 모든 부분집합을 모은 집합이다. 표기로 \(2^A\)라고도 쓴다. 유한 집합에서 \(|A| = n\)이면 \(|\mathcal{P}(A)| = 2^n\).

정리 8.3.3 (칸토어 정리)

임의의 집합 \(A\)에 대해 \(|A| < |\mathcal{P}(A)|\)이다. 즉 멱집합은 항상 원래 집합보다 진짜로 더 크다.

증명 스케치

\(|A| \le |\mathcal{P}(A)|\)는 쉽습니다. \(a \mapsto \{a\}\)이 단사예요. 핵심은 전단사가 없다는 것. 모순을 위해 전단사 \(f : A \to \mathcal{P}(A)\)가 있다고 가정합시다. 그러면 다음 부분집합을 정의해요:

\[ D = \{ a \in A : a \notin f(a) \}. \]

즉 \(D\)는 "자기가 매핑된 부분집합에 자기 자신이 들어있지 않은 원소들"의 모음입니다. \(D \subseteq A\)이므로 \(D \in \mathcal{P}(A)\)이고, \(f\)가 전사라면 어떤 \(a^* \in A\)가 있어 \(f(a^*) = D\). 이제 \(a^* \in D\)인지 묻습니다:

  • 만약 \(a^* \in D\)라면, \(D\)의 정의상 \(a^* \notin f(a^*) = D\). 모순.
  • 만약 \(a^* \notin D\)라면, \(a^* \notin f(a^*)\)이니 정의상 \(a^* \in D\). 모순.

두 경우 모두 모순이므로 전단사는 없습니다. 따라서 \(|A| < |\mathcal{P}(A)|\).

또 대각선 논법이에요! \(D\)를 정의할 때 "\(a \in f(a)\)라는 진술을 부정"한 게 본질적으로 대각선을 뒤집은 것입니다. 칸토어 대각선 논법, 정지 문제, 칸토어 정리 — 모두 같은 도구로 같은 형태의 결론을 끌어냅니다.

이 정리는 무한의 위계가 끝없이 올라간다는 뜻이기도 합니다. \(\mathbb{N}\)보다 큰 \(\mathcal{P}(\mathbb{N})\), 그보다 큰 \(\mathcal{P}(\mathcal{P}(\mathbb{N}))\), \(\dots\) 무한히 많은 "다른 크기의 무한"이 존재해요. 칸토어 본인이 이걸 발견하고 한참 어지러워했다고 합니다. 그럴 만 하죠.

노트 (\(2^A\) 표기의 정당화)

멱집합을 \(2^A\)라고 쓰는 이유: \(A\)의 부분집합은 각 원소마다 "포함/제외"의 두 선택을 한 결과로 볼 수 있어요. 즉 \(A\)에서 \(\{0, 1\}\)로 가는 함수와 일대일 대응이고, 그런 함수의 모음을 보통 \(\{0,1\}^A\)라고 표기합니다. 그래서 \(\mathcal{P}(A) = 2^A\). 유한일 땐 \(|2^A| = 2^{|A|}\)와도 일관됩니다.

참고로 이 모든 논의가 깔끔하게 이뤄지려면 "집합"이 무엇인지를 엄밀하게 정의해야 합니다. 현대 수학은 ZFC(Zermelo-Fraenkel + 선택공리)라는 공리계 위에서 작동해요. 9개 정도의 공리들이 "이런 집합은 만들 수 있다", "이렇게 모으면 또 집합이다"를 정해놓은 것입니다. 우리가 쓴 모든 집합론 기법 — 합집합, 교집합, 멱집합, 함수, 카르테시안 곱 — 이 거기서 파생됩니다.

8.4 이게 다 진짜 작동하는가? Does All This Really Work?

여기까지 따라오셨다면 한 번쯤 이런 의심이 드실 거예요. "임의의 조건으로 자유롭게 집합을 모을 수 있다면, 뭔가 위험한 일이 일어나지 않을까?" 정확한 직감입니다. 1901년 버트런드 러셀(Bertrand Russell)이 그 위험을 정확히 짚었어요.

러셀의 역설

"자기 자신을 원소로 포함하지 않는 모든 집합의 집합"을 \(R\)이라고 하자:

\[ R = \{ S : S \notin S \}. \]

이제 \(R \in R\)인가? \(R \in R\)이라면 \(R\)의 정의상 \(R \notin R\). 반대로 \(R \notin R\)이라면 정의상 \(R \in R\). 어느 쪽도 안 됩니다.

이건 또 대각선 논법의 변형이에요(이쯤 되면 패턴이 보이죠). 그리고 이 역설은 19세기 말 프레게가 막 완성하려던 "조건만 있으면 어떤 집합이든 만들어진다"는 소박한 집합론을 무너뜨립니다. 프레게는 책이 인쇄소에 있을 때 러셀의 편지를 받고 충격을 받았다는 일화가 유명해요.

해법은 "어떤 조건이든 집합을 만든다"를 포기하는 것입니다. 대신 더 신중하게, 안전한 방식으로만 집합을 만들 수 있도록 공리를 깔아요. 그게 ZFC의 핵심 아이디어입니다. 예를 들어 "이미 있는 집합 \(A\) 안에서 조건 \(\varphi\)를 만족하는 원소들만 모은다"는 분리 공리만 허용하면 \(R = \{S : S \notin S\}\) 같은 정체불명의 모음은 원천 차단됩니다. \(R\)을 만들려면 "모든 집합"이라는 모집단이 있어야 하는데, ZFC는 그것을 집합으로 인정하지 않거든요.

그럼 ZFC 자체가 무모순인지는 어떻게 아나요? 슬프게도, 안에서 증명할 수 없습니다. 1931년 쿠르트 괴델(Kurt Gödel)의 불완전성 정리가 이걸 보여줬어요.

괴델 불완전성 정리 (대단히 요약)

충분히 강력한(산술을 표현할 수 있는) 무모순 공리계는, 자기 안에서 자신의 무모순성을 증명할 수 없다. 또한 그런 공리계 안에는 참이지만 증명할 수 없는 명제가 존재한다.

이 정리는 "수학 전체를 단 하나의 완전한 공리계로 환원하자"는 힐베르트의 꿈을 영구히 종결시켰습니다. 흥미롭게도 괴델의 증명도 핵심에 자기참조와 대각선 기법이 있어요. "이 명제는 증명 불가능하다"라는 명제를 산술 안에서 코딩한 다음, 정지 문제 비슷한 모순 구조를 끌어냅니다.

또 하나, 앞서 잠깐 언급한 연속체 가설 — "\(\aleph_0 < \kappa < \mathfrak{c}\)인 무한 기수 \(\kappa\)는 없다" — 도 운명이 비슷합니다. 괴델(1940)과 코언(1963)의 결과를 합치면, 연속체 가설은 ZFC로 증명할 수도 반증할 수도 없습니다. 즉 ZFC와 독립이에요. "참인지 거짓인지 정해지지 않은 명제가 있다"는 게 아니라, "ZFC가 결정해주지 않는 명제가 있다"는 거죠. 누군가는 이걸 두고 "수학은 우리가 생각한 것보다 자유롭다"고 말하기도 합니다.

노트

이 모든 위태로움에도 불구하고, 일상의 수학과 컴퓨터과학은 ZFC 위에서 잘 작동합니다. 마치 일상의 물리학이 양자역학의 측정 문제와 무관하게 잘 굴러가듯이요. ZFC가 모순일 가능성을 완전히 배제할 순 없지만, 100년 넘게 모순이 발견되지 않았고 그 안에서 우리가 쓰는 모든 수학적 도구가 일관되게 작동합니다. 이산수학을 공부하는 입장에선 "기초가 단단하다"고 안심하고 위층 작업에 집중하면 됩니다. 다만 가끔, 이렇게 가끔, 토대가 어떻게 깔렸는지 들춰보는 것도 나쁘지 않아요.

이 챕터를 한 줄로 요약하면 이렇습니다. 무한은 한 종류가 아니고, 어떤 무한은 다른 무한보다 진짜로 크다. 그 사실을 증명한 도구(대각선 논법) 하나로 우리는 비가산성, 정지 문제의 결정 불가능성, 멱집합의 위계, 그리고 러셀과 괴델의 역설까지 한 번에 꿰뚫었습니다. 한 기법이 이렇게 멀리 데려다주는 경우는 흔치 않아요. 마음이 살짝 흔들렸다면, 정상입니다.

PART II — 구조

9 정수론 Number Theory

정수론은 한때 "가장 순수한 수학"이라고 불렸어요. 응용이 전혀 없다는 게 자랑이었죠. 그런데 이제는 사정이 완전히 달라졌습니다. 여러분이 카페 와이파이로 인터넷 뱅킹을 켜는 순간, 그 거래는 RSA라는 공개키 암호 위에서 굴러가고 RSA의 안전성은 통째로 정수론에 기대고 있어요. 이 챕터에서는 가분성과 소수, 모듈러 산술을 거쳐 RSA가 왜 작동하고 왜 어려운지까지 한 번에 따라가 봅니다.

9.1 가분성 Divisibility

정수의 세계에서 가장 먼저 익혀야 할 동사는 "나눈다"입니다. 다만 우리가 보통 쓰는 "나누기"와 달리, 정수론에서는 결과가 정수로 딱 맞아떨어지는 경우만 의미가 있어요. 예를 들어 \( 6 = 2 \cdot 3 \)이니 \( 2 \)는 \( 6 \)을 나누지만, \( 7 \)은 \( 6 \)을 나누지 못합니다.

정의 9.1.1 (가분성)

정수 \( a, b \)에 대해, 어떤 정수 \( k \)가 존재해 \( b = a \cdot k \)이면 "\( a \)가 \( b \)를 나눈다"고 하고 \( a \mid b \)로 씁니다. 이때 \( a \)는 \( b \)의 약수, \( b \)는 \( a \)의 배수예요.

몇 가지 즉시 따라오는 성질이 있습니다. \( a \mid b \)이고 \( a \mid c \)이면 어떤 정수 \( s, t \)에 대해서도 \( a \mid (sb + tc) \)예요. 즉 약수는 정수계수 선형결합 안에서도 살아남습니다. 또 \( 0 \)은 모든 정수를 약수로 가지지만 자기 자신만 \( 0 \)을 나눌 수 있는 특수한 값이고, \( 1 \)과 \( -1 \)은 모든 정수의 약수예요.

정리 9.1.2 (나눗셈 정리, Division Theorem)

임의의 정수 \( a \)와 양의 정수 \( n \)에 대해, \( a = qn + r \)이고 \( 0 \le r < n \)을 만족시키는 정수 \( q, r \)가 유일하게 존재합니다. \( q \)는 몫, \( r \)는 나머지(remainder)예요.

이 정리는 너무 당연해 보여서 처음에는 "이걸 왜 정리라고 부르지?" 싶지만, 사실 \( \gcd \)부터 모듈러 산술, 다항식 나눗셈까지 정수론의 거의 모든 알고리즘이 이 한 문장 위에 서 있어요. 나머지를 \( r = a \bmod n \)으로 표기합니다.

예제 9.1.3

\( a = 47, n = 5 \)면 \( 47 = 9 \cdot 5 + 2 \)이므로 \( q = 9, r = 2 \). \( a = -7, n = 3 \)이면 \( -7 = (-3) \cdot 3 + 2 \)이므로 나머지는 \( -1 \)이 아니라 \( 2 \)입니다. 음수일 때 \( r \ge 0 \)이라는 조건을 빠뜨리기 쉬워요.

9.2 최대공약수 The Greatest Common Divisor

두 정수의 공통된 약수 중 가장 큰 것을 최대공약수라 부르고 \( \gcd(a,b) \)로 씁니다. 초등학교에서는 약수를 모조리 나열해서 비교했지만, 큰 수에서는 이 방법이 끔찍하게 비효율적이에요. 다행히 기원전 300년경에 유클리드가 너무나 우아한 알고리즘을 남겼습니다.

정리 9.2.1 (유클리드 알고리즘의 핵심)

모든 정수 \( a, b \) (단 \( b \neq 0 \))에 대해 \[ \gcd(a, b) = \gcd(b,\ a \bmod b). \] 즉 큰 수를 작은 수로 나눈 나머지로 바꿔 가며 반복하면 결국 한쪽이 \( 0 \)이 되고, 그때 다른 쪽이 정답입니다.

예제 9.2.2 (\( \gcd(252, 198) \))

\( 252 = 1 \cdot 198 + 54 \), \( 198 = 3 \cdot 54 + 36 \), \( 54 = 1 \cdot 36 + 18 \), \( 36 = 2 \cdot 18 + 0 \). 따라서 \( \gcd(252, 198) = 18 \). 단 네 줄로 끝났어요.

def gcd(a, b):
    return a if b == 0 else gcd(b, a % b)

그런데 유클리드 알고리즘은 단지 값만 알려주는 게 아니라, 거꾸로 따라가면 \( \gcd \)를 \( a \)와 \( b \)의 정수계수 결합으로 쓰는 방법까지 줍니다. 이게 베주의 정리예요.

정리 9.2.3 (베주 항등식, Bézout)

임의의 정수 \( a, b \)에 대해 \( \gcd(a,b) = ax + by \)를 만족하는 정수 \( x, y \)가 존재합니다.

예제로 위의 \( \gcd(252, 198) = 18 \)을 거꾸로 풀면 \( 18 = 54 - 36 = 54 - (198 - 3 \cdot 54) = 4 \cdot 54 - 198 \), 다시 \( 54 = 252 - 198 \)이므로 \( 18 = 4(252 - 198) - 198 = 4 \cdot 252 - 5 \cdot 198 \). 즉 \( x = 4, y = -5 \)입니다. 이 \( x, y \)는 9.9에서 곱셈 역원을 만들 때 결정적으로 쓰이니 잘 기억해 두세요.

9.3 소수의 신비 Prime Mysteries

1보다 큰 정수 \( p \)가 \( 1 \)과 자기 자신 외의 양의 약수를 갖지 않으면 소수(prime)라고 부릅니다. 그렇지 않은 정수는 합성수(composite)예요. 사람들은 2300년 넘게 소수를 들여다봤는데도 여전히 풀지 못한 문제가 산처럼 쌓여 있습니다.

정리 9.3.1 (유클리드)

소수는 무한히 많습니다.

증명 (스케치)

유한히 많다고 가정하고 그 전부를 \( p_1, p_2, \dots, p_k \)라 합시다. 이제 \( N = p_1 p_2 \cdots p_k + 1 \)을 보세요. \( N \)은 어떤 \( p_i \)로 나누어도 나머지가 \( 1 \)이라 \( p_i \)의 배수가 아닙니다. 그런데 \( N > 1 \)이므로 어떤 소수의 배수여야 해요(이건 9.4에서 보장됩니다). 따라서 우리 목록에 없는 소수가 있다는 뜻이고, 이는 모순입니다.

"그럼 소수가 얼마나 자주 나오나?"가 다음 질문이에요. \( \pi(n) \)을 \( n \) 이하의 소수 개수라고 하면, 가우스가 십대 시절에 추측하고 1896년에 증명된 결과가 다음과 같습니다.

정리 9.3.2 (소수 정리, Prime Number Theorem)

\[ \pi(n) \sim \frac{n}{\ln n}. \] 즉 \( n \) 근처에서 무작위로 정수를 뽑았을 때 소수일 확률이 대략 \( 1/\ln n \).

한편 풀리지 않은 거대 추측들도 있어요. 쌍둥이 소수 추측은 \( p \)와 \( p+2 \)가 동시에 소수인 쌍이 무한히 많다고 주장합니다. 골드바흐 추측은 \( 4 \) 이상의 짝수는 모두 두 소수의 합으로 쓸 수 있다는 250년 묵은 문제예요. 컴퓨터로 \( 4 \cdot 10^{18} \)까지는 확인됐지만, 증명은 아직 없습니다.

노트

소수 정리가 RSA에 왜 중요할까요? 1024비트 소수 두 개가 필요할 때, "소수일 확률이 \( 1/\ln(2^{1024}) \approx 1/710 \)"이라는 사실이 있어야 안심하고 무작위 후보를 뽑을 수 있어요. 이 확률이 0에 가까웠다면 RSA 키 생성은 실용적이지 않았을 거예요.

9.4 산술 기본정리 The Fundamental Theorem of Arithmetic

"모든 정수는 소수의 곱"이라는 사실은 너무 익숙해서 정리라는 자각조차 못하기 쉬워요. 그런데 정말 따져 보면, 이 분해가 항상 가능하다는 것과 게다가 유일하다는 것은 그 자체로 묵직한 정리입니다.

정리 9.4.1 (산술 기본정리)

\( 1 \)보다 큰 모든 정수 \( n \)은 \[ n = p_1^{e_1} p_2^{e_2} \cdots p_k^{e_k} \] 의 꼴로 쓸 수 있고, 소수 \( p_1 < p_2 < \cdots < p_k \)와 양의 지수 \( e_i \)는 유일하게 결정됩니다.

증명 스케치

존재성은 강한 귀납법으로 쉽게 보입니다. \( n \)이 소수면 끝, 합성수면 \( n = ab \) (\( 1 < a, b < n \))이고 귀납가설로 \( a, b \)가 각각 소인수분해를 가지니 결합하면 됩니다. 유일성이 진짜 핵심이에요. 핵심 보조정리는 유클리드의 보조정리: 소수 \( p \)가 \( ab \)를 나누면 \( p \mid a \)이거나 \( p \mid b \). 이걸 쓰면 두 분해가 다르다고 가정해도 결국 같은 소수들의 같은 지수 모음으로 강제되어 모순이 나옵니다.

겉보기엔 당연하지만, 이 유일성은 사실 일반적인 수 체계에서 깨질 수 있어요. 예를 들어 \( \mathbb{Z}[\sqrt{-5}] \)에서는 \( 6 = 2 \cdot 3 = (1+\sqrt{-5})(1-\sqrt{-5}) \)처럼 분해가 두 가지 나옵니다. 이걸 다루려고 19세기 수학자들이 "이데알(ideal)" 개념을 발명했죠. 정수에서 유일성이 성립한다는 건 결코 공짜가 아니에요.

예제 9.4.2

\( 360 = 2^3 \cdot 3^2 \cdot 5 \). 이 분해를 알면 약수의 개수는 \( (3+1)(2+1)(1+1) = 24 \)개라고 즉시 셀 수 있어요. 모든 약수 \( d \)는 \( 2^a 3^b 5^c \) (\( 0 \le a \le 3, 0 \le b \le 2, 0 \le c \le 1 \))의 꼴이니까요.

9.5 앨런 튜링 Alan Turing

앨런 튜링(Alan Turing, 1912-1954)은 24살에 "계산 가능 함수"의 보편 모델인 튜링 기계를 정의해 컴퓨터 과학의 토대를 놓은 사람이에요. 제2차 세계대전 동안 영국 블레츨리 파크에서 독일군의 에니그마(Enigma) 암호를 깨뜨리는 데 결정적 기여를 했고, 그 덕에 전쟁이 수년 앞당겨 끝났다고 평가됩니다. 전후에는 동성애를 이유로 영국 정부에 의해 화학적 거세형을 받았고 1954년 청산가리 묻은 사과를 베어 문 채 발견됐어요(자살로 추정). 2009년 영국 총리, 2013년 여왕의 공식 사면이 있었지만 너무 늦었죠. 이 챕터에서 우리가 보게 될 모듈러 산술과 RSA는 모두 튜링이 평생 매달렸던 "암호 깨기"의 직계 후손입니다.

노트

튜링상(Turing Award)은 컴퓨터 과학의 노벨상이라 불려요. 매년 한 명에게 주어지고, 상금은 100만 달러. 이 상의 이름이 왜 튜링이어야 했는지는 9.8과 9.11을 보면 자연히 이해됩니다.

9.6 모듈러 산술 Modular Arithmetic

시계는 \( 12 \)를 넘으면 다시 \( 1 \)로 돌아갑니다. 13시는 1시와 "같은 자리"예요. 이 직관을 정수 전체에 적용한 게 모듈러 산술입니다.

정의 9.6.1 (합동, congruence)

양의 정수 \( n \)과 정수 \( a, b \)에 대해, \( n \mid (a - b) \)이면 \( a \)와 \( b \)는 \( n \)을 법으로 합동이라 하고 \[ a \equiv b \pmod{n} \] 으로 씁니다.

같은 말로, \( a \)와 \( b \)를 \( n \)으로 나눈 나머지가 같다는 뜻이에요. 이 관계는 정수 위의 동치관계입니다. 반사성·대칭성·추이성을 모두 만족하니까요. 동치관계가 있으면 동치류로 분할이 따라옵니다. \( n = 5 \)일 때 정수는 다섯 개의 동치류로 쪼개져요: \( [0], [1], [2], [3], [4] \). 각 동치류는 \( \{ \dots, -5, 0, 5, 10, \dots \} \) 같은 무한집합이에요.

모듈러 산술이 강력한 진짜 이유는 합과 곱이 동치류 위에서 잘 정의된다는 점입니다.

정리 9.6.2 (합·곱의 잘 정의됨)

\( a \equiv a' \pmod{n} \)이고 \( b \equiv b' \pmod{n} \)이면 \[ a + b \equiv a' + b' \pmod{n}, \quad a \cdot b \equiv a' \cdot b' \pmod{n}. \]

증명은 간단합니다. \( a - a' \)와 \( b - b' \)가 \( n \)의 배수이면 \( (a+b) - (a'+b') \)와 \( ab - a'b' = a(b-b') + b'(a-a') \)도 모두 \( n \)의 배수예요. 그래서 우리는 큰 수를 다룰 때 거추장스럽게 끌고 다닐 필요 없이, 매 단계마다 \( \bmod n \)으로 나머지를 취해도 결과가 같다는 자유를 얻습니다.

예제 9.6.3

\( 7^{100} \bmod 4 \)는 얼마? \( 7 \equiv 3 \equiv -1 \pmod{4} \)이므로 \( 7^{100} \equiv (-1)^{100} = 1 \pmod{4} \). 큰 수를 직접 계산할 필요가 전혀 없어요.

9.7 나머지 산술 Remainder Arithmetic

합동을 동치관계로 보고 동치류 자체를 원소로 삼는 새 집합을 만들 수 있어요. 이 집합을 \[ \mathbb{Z}_n = \{0, 1, 2, \dots, n-1\} \] 라고 쓰고, 각 원소를 "그 동치류의 대표 나머지"로 봅니다.

\( \mathbb{Z}_n \)에서의 덧셈과 곱셈은 정수의 덧셈·곱셈을 한 뒤 \( n \)으로 나머지를 취하는 것으로 정의해요. 9.6에서 이게 잘 정의된다는 걸 봤습니다. 결과적으로 \( \mathbb{Z}_n \)은 가환환(commutative ring)이 됩니다. 곧, 결합법칙·교환법칙·분배법칙이 모두 성립하고, \( 0 \)과 \( 1 \)이라는 항등원을 갖습니다.

예제 9.7.1 (\( \mathbb{Z}_5 \)의 곱셈표 일부)

\( 3 \cdot 4 = 12 = 2 \cdot 5 + 2 \)이므로 \( \mathbb{Z}_5 \)에서 \( 3 \cdot 4 = 2 \). \( 2 \cdot 3 = 6 = 1 \), \( 4 \cdot 4 = 16 = 1 \). 잘 보면 \( \mathbb{Z}_5 \)에서 0이 아닌 모든 원소가 곱셈 역원을 가져요. 이건 \( 5 \)가 소수라서 그렇습니다.

한편 \( \mathbb{Z}_6 \)에서는 사정이 다릅니다. \( 2 \cdot 3 = 6 = 0 \)이거든요. 두 0이 아닌 원소를 곱했는데 0이 나오는 일이 벌어집니다. 이런 \( \mathbb{Z}_n \)을 "영인자(zero divisor)가 있다"고 말해요. \( n \)이 합성수일 때 일어나는 현상이고, 이게 9.9에서 나올 곱셈 역원의 존재 조건과 직결됩니다.

노트

해시 함수, 체크섬, 의사난수 생성기, 빠른 멱승 등 컴퓨터에서 정수 연산을 다룰 때 \( \mathbb{Z}_n \)은 거의 항상 등장합니다. 32비트 부호 없는 정수의 산술이 곧 \( \mathbb{Z}_{2^{32}} \) 위의 산술이에요.

9.8 튜링의 코드 v2.0 Turing's Code Version 2.0

아주 단순한 암호 시나리오를 그려 봅시다. 앨리스가 밥에게 메시지 \( m \)(어떤 \( \mathbb{Z}_p \) 안의 수, \( p \)는 큰 소수)을 보내려고 합니다. 둘은 사전에 비밀키 \( k \)를 공유했고, 앨리스는 \[ c = m \cdot k \pmod{p} \] 로 암호화해서 \( c \)를 보냅니다. 밥은 \( k \)의 곱셈 역원 \( k^{-1} \)을 알고 있으니 \[ m = c \cdot k^{-1} \pmod{p} \] 로 복호화하면 끝이에요. 깔끔해 보이죠?

그런데 이 방식엔 치명적 약점이 있습니다. 공격자 이브가 메시지 두 개 \( c_1 = m_1 k \), \( c_2 = m_2 k \)를 가로챘다고 합시다. 이브는 \( c_1 \cdot c_2^{-1} = m_1 \cdot m_2^{-1} \pmod{p} \)를 계산할 수 있어요. 키 \( k \)가 깨끗이 사라집니다. 이브가 만약 메시지 한 개의 평문을 우연히 알게 된다면 — 가령 인사말 "안녕"이 거의 매번 들어간다면 — 다른 모든 메시지의 평문도 같이 무너져요.

노트 (왜 알아야 하나)

이 약점을 보면 "단일 키로 곱하기만 하는" 식의 암호로는 안전을 보장할 수 없다는 게 분명해집니다. 9.11의 RSA는 이 문제를 두 개의 다른 키, 그리고 곱셈이 아닌 멱승 연산으로 해결해요. 그 멱승의 안전성을 떠받치는 게 다음에 나오는 오일러 정리입니다.

9.9 곱셈 역원과 소거 Multiplicative Inverses and Cancelling

\( \mathbb{Z}_n \)에서 \( a \)의 곱셈 역원이란 \( a \cdot a^{-1} \equiv 1 \pmod{n} \)을 만족하는 원소입니다. 어떤 \( a \)는 역원을 가지고 어떤 건 못 가져요. 그 기준이 정확히 무엇일까요?

정리 9.9.1 (역원 존재 조건)

\( a \in \mathbb{Z}_n \)이 곱셈 역원을 가질 필요충분조건은 \( \gcd(a, n) = 1 \)입니다.

증명

(⇐) \( \gcd(a, n) = 1 \)이면 베주의 정리(9.2.3)에 의해 \( ax + ny = 1 \)인 정수 \( x, y \)가 있어요. 양변을 \( \bmod n \)으로 보면 \( ax \equiv 1 \pmod n \)이라 \( x \)가 곧 \( a^{-1} \). (⇒) \( a a^{-1} \equiv 1 \pmod n \)이면 어떤 정수 \( y \)에 대해 \( a a^{-1} - 1 = ny \), 곧 \( a a^{-1} + n(-y) = 1 \). \( a, n \)의 임의의 공약수는 \( 1 \)도 나누어야 하니 \( \gcd(a, n) = 1 \).

특히 \( n = p \)가 소수면 \( 1, 2, \dots, p-1 \) 모두가 \( p \)와 서로소이므로 모두 역원을 가져요. 그래서 \( \mathbb{Z}_p \)는 단지 환을 넘어 체(field)가 됩니다.

역원의 존재는 곧 "소거(cancellation)"의 가능 여부를 결정합니다. \( ab \equiv ac \pmod n \)에서 \( a \)를 양쪽에서 지우려면 \( a^{-1} \)을 곱해야 하는데, 그러려면 \( \gcd(a, n) = 1 \)이 필수예요. 이 조건이 없으면 일반적으로 소거가 안 됩니다. 예를 들어 \( \mathbb{Z}_6 \)에서 \( 2 \cdot 1 \equiv 2 \cdot 4 \pmod 6 \)이지만 \( 1 \not\equiv 4 \).

예제 9.9.2 (\( \mathbb{Z}_{11} \)에서 \( 7^{-1} \))

\( \gcd(7, 11) = 1 \). 확장 유클리드: \( 11 = 1 \cdot 7 + 4 \), \( 7 = 1 \cdot 4 + 3 \), \( 4 = 1 \cdot 3 + 1 \). 거꾸로 \( 1 = 4 - 3 = 4 - (7 - 4) = 2 \cdot 4 - 7 = 2(11 - 7) - 7 = 2 \cdot 11 - 3 \cdot 7 \). 따라서 \( -3 \cdot 7 \equiv 1 \pmod{11} \)이고 \( 7^{-1} \equiv -3 \equiv 8 \pmod{11} \). 검산: \( 7 \cdot 8 = 56 = 5 \cdot 11 + 1 \).

9.10 오일러 정리 Euler's Theorem

\( \mathbb{Z}_n \)에서 역원을 가지는 원소의 개수를 세는 함수가 오일러의 토션트(totient) \( \varphi(n) \)입니다.

정의 9.10.1 (오일러의 \( \varphi \) 함수)

\( \varphi(n) = |\{ a \in \{1, 2, \dots, n\} : \gcd(a, n) = 1 \}| \). 즉 \( n \)과 서로소인 \( n \) 이하 양의 정수의 개수.

몇 가지 사실. \( p \)가 소수면 \( 1, 2, \dots, p-1 \)이 모두 \( p \)와 서로소이므로 \( \varphi(p) = p - 1 \). \( p, q \)가 서로 다른 소수면 곱셈성을 이용해 \[ \varphi(pq) = (p-1)(q-1). \] 이 한 줄이 RSA의 심장이에요.

정리 9.10.2 (오일러)

\( \gcd(a, n) = 1 \)이면 \[ a^{\varphi(n)} \equiv 1 \pmod{n}. \]

증명 스케치

\( \mathbb{Z}_n \) 안에서 \( n \)과 서로소인 원소들의 집합을 \( S = \{r_1, r_2, \dots, r_{\varphi(n)}\} \)이라 합시다. \( a \)도 \( n \)과 서로소이므로, \( aS = \{a r_1, a r_2, \dots\} \)는 \( S \)의 순열입니다(소거 가능하니까). 따라서 \[ \prod_i (a r_i) \equiv \prod_i r_i \pmod n. \] \( a \)를 모아 \( a^{\varphi(n)} \prod r_i \equiv \prod r_i \), \( \prod r_i \)는 가역이므로 양변에서 지우면 \( a^{\varphi(n)} \equiv 1 \).

특수한 경우로 \( n = p \)(소수)면 \( \varphi(p) = p-1 \)이라 다음이 즉시 따라와요.

따름정리 9.10.3 (페르마의 소정리)

\( p \)가 소수이고 \( p \nmid a \)이면 \( a^{p-1} \equiv 1 \pmod{p} \).

예제 9.10.4

\( 3^{100} \bmod 7 \)은? \( \gcd(3,7)=1 \)이고 \( 3^6 \equiv 1 \pmod 7 \). \( 100 = 6 \cdot 16 + 4 \). 따라서 \( 3^{100} \equiv 3^4 = 81 \equiv 4 \pmod 7 \).

9.11 RSA 공개키 암호 RSA Public Key Encryption

이제 모든 재료가 모였어요. RSA(Rivest-Shamir-Adleman, 1977)는 인류 역사상 가장 널리 쓰인 공개키 암호이자, 정수론이 일상에 직접 들어온 사건입니다. 핵심은 "인수분해는 어렵고, 멱승은 쉽다"는 비대칭성이에요.

정의 9.11.1 (RSA 키 생성)

① 큰 서로 다른 소수 \( p, q \)를 비밀리에 고르고 \( n = pq \)로 둡니다. ② \( \varphi(n) = (p-1)(q-1) \)을 계산. ③ \( \gcd(e, \varphi(n)) = 1 \)인 정수 \( e \)를 고름(공개 지수). ④ 확장 유클리드로 \( d = e^{-1} \pmod{\varphi(n)} \)를 계산(비밀 지수). ⑤ 공개키는 \( (n, e) \), 비밀키는 \( d \). \( p, q, \varphi(n) \)은 폐기 또는 비밀 보관.

암호화·복호화는 단순한 멱승이에요. 평문 \( m \in \mathbb{Z}_n \)에 대해 \[ \text{암호화: } c = m^e \bmod n, \quad \text{복호화: } m = c^d \bmod n. \]

정리 9.11.2 (RSA의 정확성)

\( \gcd(m, n) = 1 \)이면 \( (m^e)^d \equiv m \pmod{n} \). (\( \gcd(m,n) \neq 1 \)인 경우도 중국인의 나머지 정리로 확장 가능.)

증명

키 생성에서 \( ed \equiv 1 \pmod{\varphi(n)} \)이므로 어떤 정수 \( k \)에 대해 \( ed = 1 + k\varphi(n) \). 따라서 \[ m^{ed} = m^{1 + k\varphi(n)} = m \cdot \big(m^{\varphi(n)}\big)^k. \] 오일러 정리(9.10.2)에 의해 \( m^{\varphi(n)} \equiv 1 \pmod n \), 그러므로 \( m^{ed} \equiv m \cdot 1^k = m \pmod n \).

예제 9.11.3 (작은 RSA)

\( p = 5, q = 11 \), \( n = 55 \), \( \varphi(n) = 4 \cdot 10 = 40 \). \( e = 3 \) (\( \gcd(3, 40) = 1 \)). \( d \)는 \( 3d \equiv 1 \pmod{40} \)에서 \( d = 27 \) (\( 3 \cdot 27 = 81 = 2 \cdot 40 + 1 \)). 평문 \( m = 8 \)을 암호화하면 \( c = 8^3 \bmod 55 = 512 \bmod 55 = 17 \). 복호화: \( c^{27} \bmod 55 \)는 멱승 반복 제곱법으로 계산하면 정확히 \( 8 \)이 나옵니다(직접 해 보세요).

왜 안전할까요? 이브가 공개키 \( (n, e) \)와 \( c \)를 봐도 \( m \)을 복원하려면 \( d \)가 필요하고, \( d \)를 알려면 \( \varphi(n) \)이 필요한데, \( \varphi(n) \)을 알려면 \( n \)을 \( pq \)로 인수분해해야 합니다. 그런데 1024비트, 2048비트짜리 \( n \)을 인수분해하는 알려진 알고리즘은 모두 너무 느려요. 슈퍼컴퓨터로도 수십억 년이 걸린다고 추정됩니다.

9.12 SAT은 무슨 상관? What has SAT got to do with it?

RSA의 안전은 "큰 정수의 인수분해가 어렵다"는 가정 위에 있어요. 그런데 진짜로 어렵다는 게 증명됐을까요? 슬프게도 답은 "아직 모름"입니다. 인수분해 문제 FACTOR는 NP에 속해요. 검증은 쉬우니까요. 어떤 \( n \)과 후보 \( (p, q) \)를 받으면 곱셈 한 번으로 \( pq = n \)인지 확인 가능합니다.

여기서 4장의 SAT가 등장합니다. SAT(논리식 충족 가능성)은 NP-완전 문제예요. 만약 \( P = NP \)가 증명된다면, SAT를 다항시간에 풀 수 있고, 그러면 NP에 있는 모든 문제(인수분해 포함)도 다항시간에 풀려서 RSA가 무너집니다. 반대로 \( P \neq NP \)가 증명되어도, 그것만으로는 인수분해가 어렵다는 결론이 자동으로 따라오진 않아요. 인수분해는 NP-완전성이 알려져 있지 않은 "중간 난이도" 문제로 분류되거든요.

노트 (양자 컴퓨팅)

1994년 피터 쇼어(Peter Shor)는 양자 컴퓨터에서 인수분해를 다항시간에 푸는 알고리즘을 발견했습니다. 충분히 큰 결함 허용 양자 컴퓨터가 등장하면 RSA는 한순간에 깨져요. 그래서 NIST는 격자(lattice) 기반 같은 "포스트 양자 암호"를 표준화하고 있습니다. 정수론이 일선에서 물러나는 게 아니라, 더 깊은 정수·대수 구조로 무대가 옮겨 가는 셈이에요.

요약하면, 우리가 매일 누리는 인터넷의 보안은 "인수분해는 어렵고 멱승은 쉽다"는 한 줄의 비대칭성에 걸려 있고, 그 비대칭성의 정확한 이유는 컴퓨터 과학에서 가장 큰 미해결 문제인 \( P \) vs \( NP \)와 깊이 얽혀 있습니다. 가장 순수하다던 정수론이 가장 실용적인 분야로 변신한 이야기, 이것이 이 챕터의 진짜 결말이에요.

PART II — 구조

10 유향 그래프와 부분 순서 Directed Graphs & Partial Orders

정점과 화살표만으로 인터넷의 하이퍼링크 구조, 가족 관계의 조상-후손 관계, 빌드 시스템의 작업 의존성, 그리고 대학 교과목의 선수과목 그래프까지 모두 모델링할 수 있습니다. 이 챕터에서는 화살표 방향을 가진 그래프를 정의하고, 그 위에서 자라나는 두 가지 큰 줄기 ― 도달가능성과 순서 관계 ― 를 다룹니다. 단순한 그림 하나가 어떻게 알고리즘과 수학적 구조의 출발점이 되는지 따라가 봅시다.

10.1 정점 차수 Vertex Degrees

유향 그래프(digraph)는 정점 집합 \(V\)와 정점들의 순서쌍을 원소로 갖는 간선 집합 \(E \subseteq V \times V\) 로 이루어진 쌍 \(G = (V, E)\)입니다. 무향 그래프와 달리 \((u, v)\)와 \((v, u)\)는 서로 다른 간선이에요. 화살표 \(u \to v\)는 "\(u\)에서 \(v\)로 가는 방향이 있다"는 뜻이고, 거꾸로는 가지 못할 수도 있습니다. 트위터의 팔로우 관계가 정확히 이런 구조죠. 내가 누군가를 팔로우한다고 그 사람이 나를 팔로우하는 건 아니니까요.

정의 10.1.1 (들어오는/나가는 차수)

정점 \(v \in V\)에 대해, \(v\)로 들어오는 간선의 수를 들어오는 차수(in-degree)라 하고 \(\deg^-(v)\)로 씁니다. \(v\)에서 나가는 간선의 수는 나가는 차수(out-degree)이고 \(\deg^+(v)\)로 씁니다. 식으로 쓰면 \(\deg^-(v) = |\{u : (u,v) \in E\}|\), \(\deg^+(v) = |\{w : (v,w) \in E\}|\) 이에요.

무향 그래프에서는 모든 차수의 합이 간선 수의 두 배라는 악수 정리가 있었죠. 유향 그래프에서는 한 간선이 한쪽엔 나가는 차수 1, 다른 쪽엔 들어오는 차수 1로만 기여하므로 다음이 성립합니다.

정리 10.1.2 (유향 악수 정리)

모든 유향 그래프 \(G = (V, E)\)에 대해 \[\sum_{v \in V} \deg^+(v) = \sum_{v \in V} \deg^-(v) = |E|.\]

예제 10.1.3 (웹페이지 모델)

정점이 웹페이지이고 \(u \to v\)가 "\(u\)에 \(v\)로 가는 하이퍼링크가 있다"는 의미라고 합시다. 이때 \(\deg^-(v)\)는 \(v\)를 가리키는 외부 링크의 수, 즉 \(v\)의 인기도와 관련된 양입니다. 구글 초창기 PageRank 알고리즘이 바로 이 들어오는 차수를 정교하게 가중평균한 값이에요.

10.2 워크와 경로 Walks and Paths

그래프 위에서 화살표를 따라 정점들을 옮겨다니는 행위를 형식화합시다. 길이 \(k\)인 워크(walk)는 정점-간선 교대 수열 \(v_0, e_1, v_1, e_2, \dots, e_k, v_k\)이고, 각 \(e_i\)가 \(v_{i-1} \to v_i\)인 간선이어야 합니다. 정점이나 간선이 반복되어도 괜찮아요. 같은 모서리를 두 번 지나지 않으면 트레일(trail), 같은 정점을 두 번 지나지 않으면 단순 경로(simple path)라고 부릅니다.

정의 10.2.1 (단순 경로)

워크 \(v_0 \to v_1 \to \cdots \to v_k\)가 단순 경로라는 것은 \(v_0, v_1, \dots, v_k\)가 모두 서로 다르다는 뜻이에요. 길이는 간선 수 \(k\)로 정의합니다 (정점 수 아님!).

한국어 학생들이 자주 헷갈리는 지점이 하나 있어요. 경로의 길이는 정점 수가 아니라 간선 수입니다. 정점 \(a, b, c\)를 지나는 경로 \(a \to b \to c\)의 길이는 2이지 3이 아닙니다. 사람을 셀 때는 두 명이 손을 잡으면 한 줄, 세 명이면 두 줄이듯, 간선이 한 칸이라고 생각하면 편해요.

정리 10.2.2 (워크와 경로의 관계)

유향 그래프에서 \(u\)에서 \(v\)로 가는 워크가 존재하면, \(u\)에서 \(v\)로 가는 단순 경로도 존재합니다.

증명 (스케치)

워크 위에서 같은 정점 \(w\)가 두 번 등장한다면, 두 등장 사이의 부분 워크를 통째로 잘라내도 여전히 \(u\)에서 \(v\)로 가는 워크입니다. 워크의 길이는 자연수이므로, 잘라내는 과정을 반복해도 언젠간 멈추고, 결과물에는 같은 정점이 두 번 등장하지 않습니다. 즉, 단순 경로가 됐어요.

10.3 인접 행렬 Adjacency Matrices

유향 그래프를 컴퓨터에 저장하는 가장 깔끔한 방법은 행렬을 쓰는 것입니다. 정점이 \(n\)개일 때, \(n \times n\) 행렬 \(A\)를 다음과 같이 정의해요. \(A_{ij} = 1\)이면 간선 \(v_i \to v_j\)가 있고, 아니면 \(0\). 이 행렬을 인접 행렬(adjacency matrix)이라 부릅니다. 무향 그래프와 달리 일반적으로 대칭이 아니에요.

정리 10.3.1 (워크 수 정리)

인접 행렬 \(A\)의 \(k\)제곱 \(A^k\)의 \((i, j)\) 성분은 \(v_i\)에서 \(v_j\)로 가는 길이 \(k\)인 워크의 개수와 같습니다.

증명 (귀납법 스케치)

\(k = 1\)이면 \(A^1 = A\)이고, 정의에 의해 \(A_{ij}\)는 길이 1인 워크 수(0 또는 1)입니다. 귀납 단계에서 \(A^{k+1} = A^k \cdot A\)의 \((i,j)\)성분은 \(\sum_m (A^k)_{im} A_{mj}\)인데, 이는 "중간 정점 \(v_m\)을 거쳐 \(v_i\)에서 \(v_m\)까지 길이 \(k\) 워크 수와 \(v_m \to v_j\) 직접 간선 수의 곱의 합"이에요. 정확히 길이 \(k+1\) 워크의 개수를 모든 마지막 직전 정점으로 분류해 더한 것입니다.

예제 10.3.2

정점 \(\{1, 2, 3\}\), 간선 \(\{1\to 2, 2\to 3, 3\to 1\}\)인 길이 3 사이클을 생각해봅시다. 인접 행렬은 \[A = \begin{pmatrix} 0 & 1 & 0 \\ 0 & 0 & 1 \\ 1 & 0 & 0 \end{pmatrix}.\] 계산해보면 \(A^3 = I\)가 됩니다. 즉, 자기 자신으로 돌아오는 길이 3인 워크가 정확히 하나씩 있다는 뜻이에요. 사이클을 한 바퀴 도는 그 워크 말이죠.

이 정리는 단순한 산수처럼 보이지만 강력합니다. 길이 \(k\) 워크의 수를 일일이 세지 않고 행렬 곱셈만으로 답을 얻을 수 있고, 빠른 거듭제곱 알고리즘을 쓰면 \(O(n^3 \log k)\)에 끝납니다.

10.4 워크 관계 Walk Relations

그래프 위에서 "\(u\)에서 \(v\)로 갈 수 있는가?"라는 질문은 곧 도달가능성(reachability) 문제입니다. 유향 그래프 \(G\) 위에서 워크 관계 \(G^*\)를 다음과 같이 정의합시다. \(u\, G^*\, v\) 라는 것은 \(u\)에서 \(v\)로 가는 길이 \(\geq 0\)인 워크가 존재한다는 의미입니다 (길이 0 워크는 자기 자신이에요).

정의 10.4.1 (양의 길이 도달)

비슷하게 \(G^+\)를 길이 \(\geq 1\)인 워크의 존재로 정의합니다. 둘의 차이는 자기 자신에 대한 처리예요. \(G^*\)에서는 무조건 \(u G^* u\)가 성립하지만, \(G^+\)에서는 \(u\)에서 자기 자신으로 돌아오는 사이클이 있을 때만 성립합니다.

워크 관계 \(G^*\)는 두 가지 좋은 성질을 갖습니다. 첫째, 반사적이에요. 모든 정점 \(u\)에 대해 길이 0 워크가 자명히 있죠. 둘째, 추이적입니다. \(u G^* v\)이고 \(v G^* w\)이면 두 워크를 이어 붙여 \(u G^* w\)가 됩니다. 이 두 성질을 만족하는 관계를 일반적으로 전순서(preorder)라고 부릅니다.

노트 (인접 행렬과 도달가능성)

10.3에서 \(A^k\)의 \((i,j)\) 성분이 길이 \(k\) 워크 수라고 했죠. 그러면 \(I + A + A^2 + \cdots + A^{n-1}\)의 \((i,j)\) 성분이 0이 아닐 필요충분조건이 \(v_i\)에서 \(v_j\)로 도달 가능이라는 사실이 따라와요. (단순 경로는 길이가 \(n-1\) 이하임을 이용.) 이를 부울 행렬 합으로 보면 \(\text{원-볼커-와슬} (\textrm{Warshall})\) 알고리즘의 핵심 아이디어로 이어집니다.

10.5 DAG와 스케줄링 Directed Acyclic Graphs & Scheduling

유향 그래프 중에서 사이클이 없는 것을 DAG(directed acyclic graph)라고 부릅니다. 일상 어디에나 등장해요. 메이크파일의 빌드 의존성, 강의 계획표의 선수과목, 스프레드시트의 셀 의존성, 깃 커밋 이력 모두 DAG 구조를 갖죠. "A를 하기 전에 B와 C를 끝내야 한다"라는 종류의 제약은 모두 DAG로 표현됩니다.

정의 10.5.1 (위상 정렬)

DAG \(G = (V, E)\)의 위상 정렬(topological sort)은 정점들의 일렬 나열 \(v_{\sigma(1)}, v_{\sigma(2)}, \dots, v_{\sigma(n)}\)으로서, 모든 간선 \((u, v) \in E\)에 대해 \(u\)가 \(v\)보다 앞에 오는 순서를 말합니다.

정리 10.5.2 (위상 정렬 존재성)

유향 그래프가 DAG일 필요충분조건은 위상 정렬이 존재하는 것입니다.

증명의 핵심은 "DAG에는 들어오는 차수가 0인 정점이 항상 존재한다"는 보조정리예요. 만약 모든 정점의 \(\deg^- \geq 1\)이면, 어디서든 거꾸로 화살표를 따라 무한히 갈 수 있는데 정점이 유한하므로 비둘기집에 의해 사이클이 생깁니다 ― 모순. 그래서 \(\deg^-(v) = 0\)인 정점을 골라 맨 앞에 두고 그 정점을 지운 뒤 재귀하면 위상 정렬이 만들어집니다. 이걸 알고리즘으로 옮긴 게 칸(Kahn)의 알고리즘이에요.

def topo_sort(V, E):
    indeg = {v: 0 for v in V}
    for (u, v) in E:
        indeg[v] += 1
    ready = [v for v in V if indeg[v] == 0]
    order = []
    while ready:
        u = ready.pop()
        order.append(u)
        for (a, b) in E:
            if a == u:
                indeg[b] -= 1
                if indeg[b] == 0:
                    ready.append(b)
    if len(order) != len(V):
        raise ValueError("graph has a cycle")
    return order

예제 10.5.3 (요리 의존성)

스파게티를 만든다고 합시다. "물 끓이기 → 면 삶기", "양파 썰기 → 소스 볶기", "면 삶기, 소스 볶기 → 비비기" 같은 의존성이 있다면, 가능한 위상 정렬 중 하나는 "물 끓이기, 양파 썰기, 면 삶기, 소스 볶기, 비비기"예요. 물론 "양파 썰기, 물 끓이기, ..." 식의 다른 정당한 순서도 존재합니다. 위상 정렬은 일반적으로 유일하지 않아요.

10.6 부분 순서 Partial Orders

10.5의 의존성 관계를 추상화하면 부분 순서가 됩니다. 직관적으로 부분 순서는 "어떤 둘은 비교 가능하지만, 어떤 둘은 비교 불가능"한 상황을 모형화해요.

정의 10.6.1 (부분 순서)

집합 \(A\) 위의 관계 \(\preceq\)가 다음 세 조건을 만족하면 부분 순서(partial order)라고 합니다.
(1) 반사성: 모든 \(a \in A\)에 대해 \(a \preceq a\).
(2) 반대칭성: \(a \preceq b\)이고 \(b \preceq a\)이면 \(a = b\).
(3) 추이성: \(a \preceq b\)이고 \(b \preceq c\)이면 \(a \preceq c\).
이 조건을 만족하는 쌍 \((A, \preceq)\)를 포셋(poset)이라 부릅니다.

예시는 흔합니다. 자연수 위의 \(\leq\), 양의 정수 위의 정수 나눗셈 \(|\) (\(a \mid b\)는 \(a\)가 \(b\)를 나눈다는 뜻), 집합 위의 부분집합 관계 \(\subseteq\) 등이 모두 부분 순서예요. 자연수의 \(\leq\)는 모든 둘이 비교되지만, 정수 나눗셈에서는 3과 5가 서로 나누지도 나누어지지도 않으므로 비교 불가능합니다.

정의 10.6.2 (해세 다이어그램)

포셋 \((A, \preceq)\)의 해세 다이어그램(Hasse diagram)은 부분 순서를 그림으로 보여주는 도구입니다. \(a \prec b\) (즉 \(a \preceq b\)이고 \(a \neq b\))이고 그 사이에 \(a \prec c \prec b\)인 \(c\)가 없는 경우에만 \(a\)에서 \(b\)로 화살표를 그립니다. 작은 원소를 아래에 놓고 위로 가는 선만 그려요. 추이성으로 따라오는 화살표는 생략합니다.

예제 10.6.3

\(\{1, 2, 3, 4, 6, 12\}\) 위의 정수 나눗셈 관계의 해세 다이어그램을 그리면, 1이 맨 아래, 그 위에 2와 3, 그 위에 4와 6, 맨 위에 12가 있고 \(1{-}2{-}4{-}12\), \(1{-}2{-}6{-}12\), \(1{-}3{-}6{-}12\) 같은 선들이 그어집니다. 자연수 \(\leq\) 부분순서와 달리 평면적으로 펼쳐지죠.

10.7 집합 포함으로 표현 Representing Partial Orders by Set Containment

겉모습은 다양해 보이지만, 사실 모든 부분 순서는 깊은 의미에서 본질적으로 한 가지 모양을 합니다. 그게 바로 집합 포함 관계 \(\subseteq\)예요.

정리 10.7.1 (표현 정리)

임의의 부분 순서 \((A, \preceq)\)는 어떤 집합 모음 \(\mathcal{F} \subseteq \mathcal{P}(X)\)와 그 위의 \(\subseteq\) 관계와 동형(isomorphic)입니다. 즉, 일대일 대응 \(\phi: A \to \mathcal{F}\)가 있어서 \(a \preceq b \iff \phi(a) \subseteq \phi(b)\)가 성립해요.

증명 (구성)

각 \(a \in A\)에 대해 다운셋 \(\phi(a) = \{x \in A : x \preceq a\}\)를 대응시킵니다. 그러면 \(a \preceq b\)이면 \(x \preceq a \implies x \preceq b\) (추이성)이므로 \(\phi(a) \subseteq \phi(b)\). 역으로 \(\phi(a) \subseteq \phi(b)\)이면 \(a \in \phi(a)\) (반사성)이므로 \(a \in \phi(b)\), 즉 \(a \preceq b\). 또 \(\phi(a) = \phi(b)\)이면 \(a \preceq b\)이고 \(b \preceq a\)이니 반대칭성에 의해 \(a = b\), 즉 \(\phi\)는 단사입니다.

이 정리는 단순하지만 철학적으로 시원합니다. "어떤 추상적인 순서든 결국 ‘이 원소 아래에 어떤 원소들이 있는가’의 집합 포함으로 환원된다." 즉 부분 순서론의 모든 일반론은 \(\subseteq\) 의 일반론과 같다는 뜻이에요. 컴퓨터 과학에서 타입의 서브타이핑(subtyping), 권한 격자(lattice of capabilities) 같은 구조도 결국 이 표현 정리의 그림자입니다.

노트

여기서 다운셋을 썼는데, 업셋 \(\{x : a \preceq x\}\)을 써도 비슷한 정리가 성립합니다. 단 이때는 \(\subseteq\) 방향이 반대로 뒤집혀요. 어느 쪽을 쓰든 본질은 같지만 관습적으로 다운셋 표현을 더 자주 봅니다.

10.8 전순서 Linear Orders

부분 순서 중에서 특히 임의의 두 원소가 비교 가능한 경우를 전순서(linear order, total order)라 부릅니다. 직관적으로 한 줄로 쭉 세울 수 있다는 뜻이에요.

정의 10.8.1 (전순서)

부분 순서 \((A, \preceq)\)가 전순서라는 것은, 모든 \(a, b \in A\)에 대해 \(a \preceq b\) 또는 \(b \preceq a\)가 성립함을 의미합니다. 이 추가 조건을 완전성(totality) 또는 비교 가능성(comparability)이라 불러요.

전순서의 대표 예는 자연수 \((\mathbb{N}, \leq)\), 정수 \((\mathbb{Z}, \leq)\), 실수 \((\mathbb{R}, \leq)\), 그리고 사전식 순서로 정렬한 문자열들입니다. 반면 부분집합 \(\subseteq\)나 정수 나눗셈 \(\mid\)는 전순서가 아니에요.

정리 10.8.2 (DAG의 전선형 확장)

임의의 유한 부분 순서는 어떤 전순서로 확장할 수 있습니다. 즉, 같은 집합 위에 \(\preceq \subseteq \preceq^*\)이고 \(\preceq^*\)는 전순서인 \(\preceq^*\)가 존재해요.

이 정리의 알고리즘적 사촌이 바로 위상 정렬(10.5)이에요. DAG의 도달가능성 부분 순서를 어떤 전체적 일렬 순서(스케줄)로 확장한 것이 위상 정렬이거든요. 그래서 위상 정렬은 일반적으로 유일하지 않아요. 비교 불가능했던 두 원소를 어느 쪽이 먼저인지 자유롭게 선택할 수 있기 때문입니다.

예제 10.8.3

집합 \(\{2, 3, 6\}\) 위에 정수 나눗셈을 부분 순서로 주면 \(2 \mid 6\), \(3 \mid 6\)이지만 2와 3은 비교 불가능. 이를 전순서로 확장하는 방법은 두 가지: \(2 \prec 3 \prec 6\) 또는 \(3 \prec 2 \prec 6\). 어느 쪽도 원래 부분 순서를 깨지 않습니다.

10.9 곱 순서 Product Orders

두 포셋이 있으면 자연스럽게 그 곱집합 위에 새 부분 순서를 만들 수 있습니다. 이를 곱 순서라 해요. 컴퓨터과학에서는 다차원 좌표 비교, 다중 우선순위 정렬, 동적 계획법의 부분 문제 의존 관계 등에 끊임없이 등장합니다.

정의 10.9.1 (좌표별 순서)

포셋 \((A, \preceq_A)\)와 \((B, \preceq_B)\)에 대해, 곱집합 \(A \times B\) 위의 부분 순서 \(\preceq\)를 \[(a_1, b_1) \preceq (a_2, b_2) \iff a_1 \preceq_A a_2 \text{ 그리고 } b_1 \preceq_B b_2\] 로 정의합니다. 이를 곱 순서(product order) 또는 좌표별 순서라고 불러요.

주의할 점: 두 인자 \((A, \preceq_A)\)와 \((B, \preceq_B)\)가 모두 전순서라 해도 곱 순서는 전순서가 아닙니다. 예를 들어 \((\mathbb{N}, \leq)\)와 자기 자신의 곱을 보면, \((1, 2)\)와 \((2, 1)\)은 어느 쪽도 다른 쪽을 좌표별로 지배하지 못해요. 비교 불가능합니다.

예제 10.9.2 (파레토 우월)

경제학에서의 파레토 우월(Pareto dominance)이 정확히 \(\mathbb{R}^n\) 위의 곱 순서입니다. 옵션 \(x = (x_1, \dots, x_n)\)이 옵션 \(y = (y_1, \dots, y_n)\)을 파레토 우월한다는 것은 모든 \(i\)에 대해 \(x_i \geq y_i\)이고 어딘가 적어도 한 곳에서 진짜 큰 경우에요. 다목적 최적화의 핵심 개념이고, 모든 비교 가능한 후보들 사이에서 최적 집합인 파레토 프런티어는 곱 순서의 극대 원소 집합입니다.

덧붙이자면, 사전식 순서는 곱 순서와 다른 또 한 가지 자연스런 곱 구조예요. \((a_1, b_1) <_{\text{lex}} (a_2, b_2)\)는 "\(a_1 < a_2\) 또는 \(a_1 = a_2\)이고 \(b_1 < b_2\)". 사전식 순서는 두 인자가 전순서이면 곱도 전순서로 유지되지만 직관과 어긋나는 결과(\(\epsilon\)-우월 같은)를 낳기도 하니 상황에 맞게 골라 써야 합니다.

10.10 동치관계 Equivalence Relations

부분 순서가 "어떤 것이 다른 것보다 더 큰가"를 다룬다면, 동치관계는 "두 원소가 같은 종류인가"를 다룹니다. 약간 다른 세계지만 정의 형식은 비슷해요.

정의 10.10.1 (동치관계)

집합 \(A\) 위의 관계 \(\sim\)이 다음을 만족하면 동치관계(equivalence relation)입니다.
(1) 반사성: \(a \sim a\).
(2) 대칭성: \(a \sim b \implies b \sim a\).
(3) 추이성: \(a \sim b\)이고 \(b \sim c\)이면 \(a \sim c\).
부분 순서와의 차이는 반대칭성 대신 대칭성을 요구한다는 점이에요.

동치관계의 가장 친숙한 예가 모듈로 합동 \(a \equiv b \pmod n\)입니다. 같은 나머지를 갖는 정수들끼리 같다고 보는 거죠. 또 7장에서 다뤘던 함수의 동치, 도형의 합동 등도 모두 동치관계입니다.

정의 10.10.2 (동치류와 분할)

동치관계 \(\sim\)에 대해, \(a\)의 동치류(equivalence class)를 \([a] = \{x \in A : x \sim a\}\)로 정의합니다. 동치류들의 모임 \(\{[a] : a \in A\}\)을 몫집합(quotient set)이라 부르고 \(A/\sim\)이라 씁니다.

정리 10.10.3 (분할 정리)

집합 \(A\) 위의 동치관계 \(\sim\)는 \(A\)의 분할(partition)을 만들어냅니다. 즉, 동치류들은 (1) 비어있지 않고, (2) \(A\)를 덮으며, (3) 서로 다른 두 동치류는 교집합이 빕니다. 역으로, 임의의 분할은 어떤 동치관계에서 나옵니다.

이 정리 덕분에 "동치관계"와 "분할"은 같은 개념의 두 얼굴이라고 봐도 됩니다. 한쪽에서 다른 쪽으로 자유롭게 오갈 수 있어요. 컴퓨터과학에서는 그래프의 강한 연결요소(SCC), 합동 연산을 통한 자료구조(union-find), 컴파일러의 등가 변수 분석 등에서 매일같이 등장합니다.

10.11 관계 성질 요약 Summary of Relational Properties

10장에서 등장한 다양한 관계의 성질을 한 표로 정리하고 마무리합시다. 각 행은 관계의 종류이고, 각 열은 그 관계가 만족해야 하는 조건이에요. 같은 정의를 외우려 하기보단, 어떤 조합이 어떤 의미를 갖는지 음미하면 좋습니다.

관계 종류 반사성 대칭성 반대칭성 추이성 완전성 대표 예
전순서(preorder) O O 워크 관계 \(G^*\)
부분 순서(partial order) O O O \(\subseteq\), \(\mid\)
엄격 부분 순서(strict) X 비반사 + 비대칭 O \(\subsetneq\), \(<\)
전순서(linear order) O O O O \((\mathbb{R}, \leq)\)
동치관계(equivalence) O O O \(\equiv \pmod n\)
일반 관계(general) 임의의 \(R \subseteq A \times B\)

노트 (관계 = 그래프)

이 챕터의 진짜 메시지는 단순합니다. 유향 그래프 = 관계. 정점 \(A\) 위의 모든 이항관계 \(R \subseteq A \times A\)는 곧 화살표가 있는 그림이고, 화살표의 패턴이 반사적이냐, 대칭적이냐, 추이적이냐에 따라 우리는 그것을 부분 순서, 동치관계, 워크 관계 등 다양한 이름으로 부를 뿐이에요. 이산수학의 큰 강 두 갈래(그래프와 관계)가 한 강이라는 사실이 이 챕터의 통찰입니다.

다음 챕터에서는 화살표 방향을 잊은 무향 그래프로 돌아가, 연결성과 트리의 세계를 본격적으로 탐험합니다. 거기서 만나는 도구들도 결국 이 챕터에서 다진 관계의 언어 위에 세워진 것임을 기억하면 좋겠어요.

PART II — 구조

11 통신 네트워크 Communication Networks

수십억 개의 컴퓨터가 어떻게 서로 말을 걸까요? 그 답은 결국 네트워크 토폴로지의 수학에 있습니다. 이 챕터에서는 그래프를 도구 삼아 데이터 센터, 멀티프로세서, 인터넷의 뼈대를 모델링하고, 어떤 토폴로지가 빠르고 싸고 막히지 않는지 따져 봅니다. 그래프 이론이 추상적 놀이가 아니라 진짜 엔지니어링 도구라는 사실을 보여 주는 챕터예요.

11.1 라우팅 Routing

네트워크라고 하면 거창해 보이지만, 본질은 단순합니다. 입력이라 부르는 점들 \(I_1, I_2, \dots, I_N\)이 있고, 출력이라 부르는 점들 \(O_1, O_2, \dots, O_N\)이 있습니다. 그리고 각 입력은 어딘가의 출력으로 메시지를 보내고 싶어 합니다. 데이터 센터에서는 입력이 서버, 출력도 서버. 멀티코어 칩에서는 입력이 코어, 출력은 메모리 뱅크. 본질은 같습니다.

문제는 입력과 출력 사이를 직선으로 잇는 것이 비현실적이라는 점이에요. \(N\)개 입력과 \(N\)개 출력을 모두 직접 연결하면 선이 \(N^2\)개 필요합니다. \(N=10^6\)이면 선이 \(10^{12}\)개. 이걸 진짜로 깔 사람은 없겠죠. 그래서 가운데에 스위치(switch)들을 두고, 메시지가 스위치를 거쳐 가도록 만듭니다. 결국 우리가 다루는 건 정점이 입력·스위치·출력이고 간선이 통신선인 그래프예요.

정의 11.1.1 (통신 네트워크)

입력 집합 \(\mathcal{I} = \{I_1, \dots, I_N\}\)과 출력 집합 \(\mathcal{O} = \{O_1, \dots, O_N\}\), 그리고 스위치 집합 \(S\)로 이루어진 그래프 \(G\)를 통신 네트워크라 부릅니다. 보통 모든 \(I_i\)는 차수 1, 모든 \(O_j\)도 차수 1로 두고, 가운데 스위치들이 라우팅을 담당합니다.

이 위에서 진짜 풀어야 할 문제는 무엇일까요? 어떤 입력이 어떤 출력으로 가고 싶다는 요청이 한꺼번에 들어옵니다. 이 요청을 깔끔하게 모델링한 것이 순열 라우팅(permutation routing)입니다.

정의 11.1.2 (라우팅 문제)

\(\{1, \dots, N\}\) 위의 순열 \(\pi\)가 주어지면, 모든 \(i\)에 대해 입력 \(I_i\)에서 출력 \(O_{\pi(i)}\)로 가는 경로 \(P_i\)를 찾는 것이 라우팅 문제입니다. 경로들의 모음 \(\{P_1, \dots, P_N\}\)을 그 순열에 대한 라우팅이라 부릅니다.

예제 11.1.3

입력 4개, 출력 4개, 가운데 스위치 한 개만 있는 가장 단순한 네트워크를 상상해 봅시다. 모든 입력이 그 스위치로 들어가고, 스위치가 적절히 출력으로 보내 줍니다. 어떤 순열이 와도 라우팅은 가능해요. 다만 모든 메시지가 스위치 하나를 통과해야 하니, 한 정점에 부하가 몰립니다. "되긴 되는데 막히는" 전형적인 예입니다.

여기서 우리는 라우팅이 가능한가만 묻는 게 아니라, 얼마나 좋게 가능한가를 묻고 싶어집니다. 경로가 너무 길면 지연(latency)이 커지고, 한 간선에 너무 많이 몰리면 병목이 되니까요. 그래서 다음 절에서는 네트워크의 품질을 재는 자(尺)들을 정의합니다.

11.2 라우팅 측정 Routing Measures

네트워크를 평가하는 자는 크게 네 가지입니다. 지름, 혼잡도, 비용(스위치 수), 그리고 대역폭. 하나만 가지고는 좋은 네트워크를 못 만들고, 항상 트레이드오프가 있다는 점을 미리 강조해 둡니다.

정의 11.2.1 (지름)

네트워크 \(G\)의 지름(diameter)은 \[ \mathrm{diam}(G) = \max_{u, v} \, d(u, v) \] 입니다. 여기서 \(d(u,v)\)는 \(u\)와 \(v\) 사이의 최단 경로 길이고, 보통 입력에서 출력까지의 거리를 따집니다. 지름은 라우팅의 최악 지연을 직관적으로 잡아 주는 양이에요.

정의 11.2.2 (혼잡도)

순열 \(\pi\)에 대한 라우팅 \(\{P_1, \dots, P_N\}\)이 주어졌을 때, 그 라우팅의 혼잡도(congestion)는 한 간선을 지나는 경로의 최대 수입니다. \[ \mathrm{cong}(\{P_i\}) = \max_{e \in E(G)} \,\bigl| \{ i : e \in P_i \} \bigr|. \] 그리고 네트워크 자체의 혼잡도는 모든 순열에 대해 라우팅을 가장 잘 골랐을 때의 최댓값으로 정의합니다. 즉 \[ \mathrm{cong}(G) = \max_{\pi} \, \min_{\{P_i\}} \mathrm{cong}(\{P_i\}). \] 어떤 순열이 와도 이 값 이하로 막힘을 줄일 수 있다는 뜻이에요.

혼잡도 정의가 살짝 어지러울 수 있어요. "최악의 순열을 가져와 보세요. 그래도 우리는 라우팅을 잘 골라서 한 간선당 통과 메시지 수를 이 정도로 막을 수 있어요." 이 약속의 보증치가 \(\mathrm{cong}(G)\)입니다.

정의 11.2.3 (비용과 대역폭)

비용은 보통 스위치의 수, 또는 간선의 수, 또는 각 스위치의 차수로 잽니다. 칩으로 만들 때 핀 수와 면적이 곧 돈이라 매우 실용적인 척도예요. 대역폭(bandwidth)은 단위 시간당 통과시킬 수 있는 메시지 수로, 이상적인 모델에서는 혼잡도의 역수에 비례한다고 봐도 좋습니다.

노트

지름은 짧을수록 좋고, 혼잡도도 작을수록 좋고, 비용도 적을수록 좋습니다. 그런데 셋이 동시에 작아지지 않습니다. 어디를 죄면 어딘가가 늘어나요. 다음 절은 본질적으로 이 트레이드오프 카탈로그입니다.

예제 11.2.4

예제 11.1.3의 단일 스위치 네트워크는 지름이 2(입력→스위치→출력)로 매우 짧습니다. 비용도 스위치 1개로 최소. 그런데 모든 메시지가 같은 두 간선을 공유하니 혼잡도가 \(N\)에 가깝죠. 짧고 싸지만 막혀 죽는 구조입니다.

이제 자(尺)는 다 만들었으니, 실제 네트워크 디자인들을 그 자에 대 봅시다.

11.3 네트워크 디자인 Network Designs

네트워크 토폴로지의 동물원에는 별별 친구들이 다 있지만, 교과서에 빠지지 않는 네 가지를 살펴봅니다. 완전 이분 그래프, 2D 메시, 버터플라이, 그리고 베네스 네트워크.

완전 이분 그래프 \(K_{N,N}\)

모든 입력을 모든 출력에 직접 연결한 구조입니다. 입력과 출력 사이 간선이 \(N^2\)개. 지름은 1, 혼잡도는 1(각 입력은 자기 출력으로 가는 한 줄만 쓰면 끝). 완벽해 보이죠? 그런데 비용이 \(\Theta(N^2)\)이라 \(N\)이 커지면 미친 짓이 됩니다.

정리 11.3.1 (완전 이분 그래프의 측정치)

\(K_{N,N}\)의 지름은 1, 모든 순열 라우팅의 혼잡도는 1, 간선 수는 \(N^2\), 각 정점의 차수는 \(N\)입니다.

2D 메시(grid)

\(N = n^2\)개의 입력과 출력을 \(n \times n\) 격자에 늘어놓은 구조입니다. 각 격자칸이 작은 스위치이고, 옆 칸끼리만 직접 연결됩니다. 만들기 쉽고(인접 연결만 있으니까) 비용도 \(\Theta(N)\)으로 매우 쌉니다. 대신 한 끝에서 다른 끝까지 가려면 격자를 가로질러야 해서 지름이 \(\Theta(\sqrt{N})\)에 달해요.

예제 11.3.2

\(n=4\)인 \(4 \times 4\) 메시. 입력 \(I_{(0,0)}\)에서 출력 \(O_{(3,3)}\)으로 가려면 가로 3 + 세로 3 = 6 칸을 거쳐야 합니다. 지름은 약 \(2(n-1)\)이에요. 한편 모든 메시지가 격자 한가운데 가로선을 가로지르는 최악 순열에서는 그 가로선의 \(n\)개 간선에 \(\Theta(n^2) = \Theta(N)\)개 경로가 몰려 혼잡도가 \(\Theta(\sqrt{N})\) 정도 됩니다.

버터플라이 네트워크

\(N = 2^n\)일 때, 입력 측 \(N\)개·출력 측 \(N\)개와 가운데 \(n+1\)개 층을 두고, 각 층마다 비트 하나씩을 "고를지 말지" 결정하는 스위치를 배치하는 구조입니다. 입력에서 출력까지 정확히 \(n+1\) 단계를 거치고, 각 단계에서 한 비트를 결정하면 모든 출력에 도달할 수 있어요.

정리 11.3.3 (버터플라이의 측정치)

\(N = 2^n\)인 버터플라이 네트워크의 지름은 \(n+1 = \log_2 N + 1\), 스위치 수는 \(\Theta(N \log N)\), 각 스위치의 차수는 상수(보통 4). 그러나 최악 순열의 혼잡도는 \(\Theta(\sqrt{N})\)에 이릅니다.

지름이 \(\log N\)으로 정말 작아진다는 점에 주목하세요. 메시 대비 지수적으로 짧습니다. 대신 어떤 못된 순열을 가져오면 한 간선에 \(\sqrt{N}\) 개의 경로가 몰리는 일이 벌어집니다. "빠르긴 한데 운 나쁜 패턴에서는 막힌다"가 버터플라이의 성격이에요.

베네스(Beneš) 네트워크

버터플라이의 혼잡도 문제를 해결하는 영리한 트릭은, 버터플라이를 두 개 등을 맞대고 붙여 거의 거울처럼 이어붙이는 것입니다. 이렇게 만든 것이 베네스 네트워크예요. 지름은 \(2\log_2 N\) 정도로 살짝 늘지만, 어떤 순열이 와도 혼잡도 1로 라우팅이 가능하다는 굉장한 성질을 얻습니다.

정리 11.3.4 (베네스의 라우팅)

\(N = 2^n\)인 베네스 네트워크에서는 임의의 순열 \(\pi\)에 대해 모든 경로가 서로 간선을 공유하지 않는 라우팅이 존재합니다. 즉 \(\mathrm{cong}(G) = 1\). 지름은 \(2n+1 = \Theta(\log N)\), 스위치 수는 \(\Theta(N \log N)\)입니다.

증명 스케치

핵심 아이디어는 재귀입니다. 베네스 네트워크는 첫 층과 마지막 층을 빼고 나면 두 개의 작은 베네스 네트워크가 위·아래로 들어 있는 구조예요. 각 입력은 첫 층에서 위쪽 부분망으로 갈지 아래쪽으로 갈지 둘 중 하나를 골라야 하고, 같은 짝이 되는 출력의 마지막 층 짝은 그 반대로 가야 충돌이 안 납니다. 이 조건을 그래프 색칠 문제로 옮기면 이분 그래프의 2-색칠 가능성으로 환원되고, 홀수 길이 사이클이 없음을 보이면 됩니다. 작은 부분망에서도 같은 논리를 재귀적으로 적용하면 전체 라우팅이 만들어져요.

한눈에 보는 비교표

네 가지 디자인을 같은 자(尺)로 정렬하면 다음과 같습니다.

네트워크 지름 혼잡도 스위치 수 스위치 차수
완전 이분 \(K_{N,N}\) \(1\) \(1\) \(\Theta(N)\) \(\Theta(N)\)
2D 메시 \(\Theta(\sqrt{N})\) \(\Theta(\sqrt{N})\) \(\Theta(N)\) \(O(1)\)
버터플라이 \(\Theta(\log N)\) \(\Theta(\sqrt{N})\) \(\Theta(N \log N)\) \(O(1)\)
베네스 \(\Theta(\log N)\) \(1\) \(\Theta(N \log N)\) \(O(1)\)

노트

표를 가만히 보면 베네스가 거의 만능처럼 보입니다. 지름은 \(\log N\), 혼잡도는 1, 스위치 수는 \(N\log N\), 차수는 상수. 그런데 빠진 비용이 하나 있어요. 베네스는 라우팅 자체를 계산하는 비용이 듭니다. 임의의 순열을 받았을 때 충돌 없는 경로를 정해 주는 알고리즘이 \(O(N \log N)\) 정도 시간을 먹어요. 메시지가 자주 바뀌는 환경이면 이 부담이 작지 않습니다. 그래서 실제 데이터 센터는 종종 메시 + 그 위에 트리(fat-tree, Clos 네트워크 같은) 같은 하이브리드를 씁니다.

마지막으로 이 챕터의 메시지를 한 줄로 정리해 두면. 통신 네트워크 설계는 지름·혼잡도·비용이라는 삼각형 안에서 어디에 무게를 둘지 고르는 게임입니다. 그래프라는 한 가지 언어로 셋을 모두 정량화할 수 있다는 사실이, 이산수학이 시스템 설계에 끼친 가장 우아한 기여 중 하나예요. 다음 챕터에서는 이 그래프 위에서 걷기가 갖는 또 다른 면 — 연결성, 트리, 색칠 — 을 살펴봅니다.

PART II — 구조

12 단순 그래프 Simple Graphs

단순 그래프 — 점 몇 개와 선 몇 개. 그러나 인터넷, 사회, 분자, 일정표가 다 이 안에 있습니다. 점은 객체, 선은 객체 사이의 어떤 관계를 뜻하죠. 이 단순한 추상 위에서 우리는 친구 관계의 평균, 비행기 노선의 색칠, 회로의 연결성, 그리고 해밀턴이 평생 풀고 싶었던 일주 문제까지 다룰 수 있습니다. 이 챕터에서는 단순 그래프의 정의부터 시작해 동형, 이분 그래프와 매칭, 채색, 워크와 연결성, 오일러·해밀턴 회로, 그리고 트리까지 — 그래프 이론의 가장 기본적이고 가장 자주 쓰이는 도구들을 손에 익혀 봅니다.

12.1 정점 인접과 차수 Vertex Adjacency and Degrees

그래프 이론에서 가장 먼저 배우는 종류의 그래프는 단순 그래프입니다. "단순"이라는 말은 두 가지 제한을 뜻해요. 같은 두 정점을 잇는 변이 두 개 이상 존재하지 않고(다중변 금지), 자기 자신을 잇는 변(루프)도 없다는 것이죠. 단순 그래프는 사람·도시·웹페이지처럼 "쌍이 관계 있느냐 없느냐"만 묻는 이산 구조에 자연스럽게 들어맞습니다.

정의 12.1.1 (단순 그래프)

단순 그래프 \( G \)는 순서쌍 \( G = (V, E) \)로 쓰며, 여기서 \( V \)는 비어 있지 않은 유한 집합(정점 집합), \( E \)는 \( V \)의 서로 다른 두 원소로 이루어진 부분집합들의 집합(변 집합)입니다. 즉 \( E \subseteq \binom{V}{2} \). 변 \( \{u, v\} \)가 \( E \)에 있으면 \( u \)와 \( v \)는 서로 인접(adjacent)하다고 하며, \( u \sim v \)로 적습니다.

변이 정점에 닿아 있을 때 우리는 그 변이 그 정점에 접속(incident)한다고 말합니다. 정점 \( v \)에 접속하는 변의 개수를 \( v \)의 차수(degree)라 하고 \( \deg(v) \)로 씁니다. 단순 그래프에서는 자기 자신과 잇는 루프가 없으므로 \( \deg(v) \)는 그냥 \( v \)의 이웃의 개수와 같습니다.

예제 12.1.2

정점 4개 \( \{a, b, c, d\} \)에 변이 \( \{a,b\}, \{b,c\}, \{c,d\}, \{a,c\} \)인 그래프를 봅시다. 차수를 세어 보면 \( \deg(a) = 2, \deg(b) = 2, \deg(c) = 3, \deg(d) = 1 \). 이 차수의 합은 \( 2+2+3+1 = 8 \)이고 변의 개수는 4개. 합이 정확히 변 개수의 두 배입니다. 우연일까요?

우연이 아닙니다. 모든 변은 양 끝의 두 정점 차수에 각각 1씩 기여합니다. 그래서 모든 정점의 차수를 더하면, 모든 변이 두 번씩 세어지죠.

정리 12.1.3 (핸드셰이크 보조정리, Handshake Lemma)

임의의 단순 그래프 \( G = (V, E) \)에 대해 \[ \sum_{v \in V} \deg(v) = 2|E|. \]

따름정리 12.1.4

임의의 단순 그래프에서 차수가 홀수인 정점의 개수는 짝수다.

이름이 "악수 보조정리"인 까닭은 이래요. 파티에서 사람들이 악수를 했을 때, 모든 사람이 악수한 횟수의 합은 항상 짝수다 — 모든 악수는 두 사람의 카운트를 1씩 올리니까요. 컴퓨터과학에서는 그래프의 평균 차수 \( \bar d = 2|E|/|V| \)를 추정할 때 이 식이 그대로 들어갑니다.

12.2 인구 통계의 이상 Sexual Demographics in America

핸드셰이크 보조정리는 작은 식 같지만, 통계 기사를 비판하는 무기로 쓰일 수 있습니다. 미국에서 흔히 인용되던 설문 결과 하나를 가져와 봅시다. "남성은 평생 평균 7명의 이성 파트너를 가지며, 여성은 4명을 가진다." 이런 식의 보고서, 어디서 본 적 있죠? 그래프 이론으로 5초만 생각해 보면 이 숫자는 동시에 옳을 수 없다는 것을 알 수 있습니다.

이성 관계라는 그래프 \( G \)를 그려 봅시다. 정점은 사람이고, 변은 "이 두 사람이 한 번이라도 이성 파트너 관계였다"는 사실. 그러면 한쪽 끝은 남자, 다른 쪽 끝은 여자인 변만 있는 셈이죠. 이런 그래프를 우리는 곧 이분 그래프(bipartite)라 부르게 됩니다.

남성 집합을 \( M \), 여성 집합을 \( W \)라 하고, 모든 변의 양 끝이 한쪽은 \( M \), 한쪽은 \( W \)라고 합시다. 핸드셰이크 보조정리에서 차수의 합은 변 개수의 2배지만, 이 합을 두 그룹으로 쪼개면 \[ \sum_{m \in M} \deg(m) \;+\; \sum_{w \in W} \deg(w) = 2|E|. \] 그런데 이분 그래프에서는 한 변마다 \( M \) 쪽 차수에 1, \( W \) 쪽 차수에 1을 더하므로 \[ \sum_{m \in M} \deg(m) = |E| = \sum_{w \in W} \deg(w). \] 즉 남자들의 파트너 수의 합과 여자들의 파트너 수의 합은 정확히 같아야 합니다.

노트 (그래서 평균은?)

남성 평균 차수는 \( \bar d_M = |E|/|M| \), 여성 평균 차수는 \( \bar d_W = |E|/|W| \). 두 평균의 비는 \[ \frac{\bar d_M}{\bar d_W} = \frac{|W|}{|M|}. \] 미국 성인 남녀 인구는 거의 1:1이므로 이 비도 거의 1이어야 합니다. 그런데 7/4 ≈ 1.75라고요? 그러려면 여성 인구가 남성 인구의 1.75배여야 하죠. 그럴 리 없습니다.

그래서 이 종류의 통계는 수학적으로 동시에 참일 수 없습니다. 누군가는 거짓말을 하거나, 기억을 잘못하거나, 표본이 편향되었거나 — 적어도 둘 중 하나는 사실과 거리가 멉니다. 사회학자들이 이미 알고 있는 현상이지만, 핵심을 한 줄로 잡아 주는 것은 결국 핸드셰이크 보조정리예요. 그래프적 사고는 가끔 신문 기사 한 면을 통째로 의심하게 만듭니다.

12.3 흔히 보는 그래프들 Some Common Graphs

그래프 이론을 공부하다 보면 같은 모양의 그래프가 반복해서 등장합니다. 이름을 붙여 두면 편하니까, 자주 보는 다섯 종류만 정리해 둡시다.

정의 12.3.1 (이름 있는 그래프들)

아래에서 \( n, m \ge 1 \)은 자연수입니다.

  • 완전 그래프 \( K_n \): 정점이 \( n \)개이고, 서로 다른 두 정점 사이에 모두 변이 있는 그래프. 변의 개수는 \( \binom{n}{2} \).
  • 완전 이분 그래프 \( K_{m,n} \): 정점 집합이 \( A \cup B \), \( |A|=m, |B|=n \)이고, \( A \) 안에서나 \( B \) 안에서는 변이 없으며, \( A \)와 \( B \) 사이에는 모든 쌍이 변으로 연결되어 있는 그래프. 변의 개수는 \( mn \).
  • 경로 그래프 \( P_n \): 정점 \( v_1, v_2, \dots, v_n \)이 일렬로 \( v_i \sim v_{i+1} \)만 변으로 연결된 그래프. 변의 개수는 \( n-1 \).
  • 사이클 그래프 \( C_n \) (\( n \ge 3 \)): \( P_n \)의 양 끝 \( v_1, v_n \)을 한 변으로 더 이은 것. 변의 개수는 \( n \).
  • 하이퍼큐브 \( Q_n \): 정점 집합이 \( \{0,1\}^n \)이고, 두 정점이 정확히 한 좌표에서만 다를 때 변이 있는 그래프. 정점 \( 2^n \)개, 변 \( n \cdot 2^{n-1} \)개.

예제 12.3.2

\( Q_3 \)을 손으로 그려 봅시다. 정점은 \( 000, 001, 010, 011, 100, 101, 110, 111 \) 8개. 변은 한 비트만 다른 쌍들 — 예를 들어 \( 010 \sim 011 \), \( 010 \sim 000 \), \( 010 \sim 110 \). 그림으로 그리면 정확히 정육면체 모양이 나옵니다. 그래서 이름이 "큐브"죠. \( Q_n \)은 병렬 컴퓨터의 통신 네트워크, 비트 오류 보정 부호의 코드워드 집합 등에서 자주 등장합니다.

노트

\( K_n \)은 모든 정점의 차수가 \( n-1 \)로 같고, \( C_n \)은 모두 차수 2, \( Q_n \)은 모두 차수 \( n \). 이렇게 모든 정점의 차수가 같은 그래프를 정칙 그래프(regular graph), 차수 \( k \)이면 \( k \)-정칙이라 부릅니다. 정칙성은 대칭성의 한 형태이고, 분석이 훨씬 쉬워지는 좋은 성질입니다.

12.4 동형 Isomorphism

두 그래프가 그림으로 보면 다르게 생겼는데, 정점 이름만 바꿔 주면 사실은 같은 그래프인 경우가 많습니다. 이 "이름 바꾸기로 같다"는 관계가 동형입니다.

정의 12.4.1 (그래프 동형)

두 단순 그래프 \( G_1 = (V_1, E_1) \)와 \( G_2 = (V_2, E_2) \)가 동형(isomorphic, \( G_1 \cong G_2 \))이라 함은, 일대일 대응 \( f: V_1 \to V_2 \)가 존재해서 모든 \( u, v \in V_1 \)에 대해 \[ \{u, v\} \in E_1 \iff \{f(u), f(v)\} \in E_2 \] 가 성립하는 것이다.

쉽게 말해 정점에 이름표를 다시 붙여서 변의 모임이 정확히 일치하게 만들 수 있느냐는 것이죠. 동형은 동치 관계입니다(반사·대칭·추이). 그래서 그래프를 분류할 때 우리는 보통 동형류(isomorphism class) 단위로 셉니다.

두 그래프가 동형인지 보이려면 적절한 \( f \)를 구체적으로 제시하면 됩니다. 동형이 아님을 보이는 게 더 흥미로운데, 이때 쓰는 도구가 동형 invariant입니다. 동형이라면 보존되어야 하는 양 — 정점 수, 변의 수, 차수 수열, 사이클의 길이, 연결 성분의 개수, 보 그래프의 차수 수열 등 — 가운데 하나라도 다르면 두 그래프는 절대 동형일 수 없습니다.

예제 12.4.2

정점 5개의 두 그래프 \( G_1, G_2 \). \( G_1 \)의 차수 수열은 \( (3, 3, 2, 2, 2) \), \( G_2 \)의 차수 수열은 \( (3, 3, 3, 2, 1) \). 차수 수열이 다르므로 두 그래프는 동형이 아닙니다. 그림 그릴 필요도 없죠.

노트 (그래프 동형 문제)

일반적인 두 그래프가 동형인지 판정하는 알고리즘은 효율성 면에서 미묘합니다. P인지 NP-완전인지조차 오랫동안 미지였고, 2017년경 László Babai가 준다항식 시간 알고리즘을 제시한 이후로도 결정적인 다항 시간 알고리즘은 알려져 있지 않습니다. 즉 그래프 동형 문제는 아직 살아 있는 연구 주제입니다.

12.5 이분 그래프와 매칭 Bipartite Graphs & Matchings

이분 그래프는 정점을 두 그룹 \( L, R \)로 쪼갤 수 있고, 모든 변의 두 끝이 한쪽씩에 들어가는 그래프입니다(같은 쪽 안에서는 변이 없음). 12.2의 이성 파트너 그래프, 학생-수업 그래프, 작업자-할 일 그래프, 이미지 픽셀-라벨 그래프 등 현실에서 정말 흔히 나옵니다.

정의 12.5.1 (매칭과 완전 매칭)

그래프 \( G \)의 매칭(matching)이란, 변들의 부분집합 \( M \subseteq E \)으로서 어느 두 변도 정점을 공유하지 않는 것이다. 이분 그래프 \( G = (L \cup R, E) \)에서 \( M \)이 \( L \)의 모든 정점을 덮으면(즉 모든 \( \ell \in L \)이 \( M \)의 어떤 변에 속하면) L-완전 매칭이라 한다.

완전 매칭이 존재하기 위한 깔끔한 조건이 있습니다. 부분집합 \( S \subseteq L \)에 대해 \( S \)의 이웃들의 집합 \( N(S) = \{ r \in R : \exists \ell \in S, \{\ell, r\} \in E \} \)를 봅시다. 만약 어떤 \( S \)에 대해 \( |N(S)| < |S| \)라면, \( S \) 안의 사람들이 \( N(S) \) 안의 자리 안에서 서로 다른 짝을 모두 찾을 수 없죠 — 비둘기집 원리. 놀라운 것은 이 비둘기집 조건의 역도 성립한다는 것입니다.

정리 12.5.2 (홀의 정리, Hall's Marriage Theorem)

이분 그래프 \( G = (L \cup R, E) \)에 \( L \)-완전 매칭이 존재할 필요충분조건은 \[ \forall S \subseteq L, \quad |N(S)| \ge |S|. \]

증명 (스케치)

(⇒) 완전 매칭 \( M \)이 있으면 임의의 \( S \subseteq L \)의 \( M \)-짝들이 \( N(S) \)에 \( |S| \)개 이상 들어가 있으므로 \( |N(S)| \ge |S| \).

(⇐) 귀납법. \( |L| = 1 \)이면 자명. 일반 단계에서 두 경우. (i) 모든 \( \emptyset \neq S \subsetneq L \)에서 \( |N(S)| > |S| \)이면, 임의의 \( \ell \in L \)과 그 이웃 \( r \in R \)을 짝지어 그래프에서 빼도 남은 그래프가 여전히 홀 조건을 만족한다. 귀납 가설로 끝. (ii) 어떤 \( \emptyset \neq S \subsetneq L \)에서 \( |N(S)| = |S| \)이면, 이 \( S \)와 \( N(S) \)로 만든 부분 그래프, 그리고 그 보충부에서 각각 홀 조건이 유지됨을 보이고 두 매칭을 합친다.

홀의 정리는 결혼 정리(marriage theorem)라고도 불립니다. \( L \)을 신부, \( R \)을 신랑이라 두고 누가 누구와 결혼할 수 있는지를 변으로 표시했을 때, 모든 신부가 자기가 받아들일 수 있는 사람과 짝을 이룰 수 있는 조건이 위와 같다는 동화 같은 해석이 있죠. 컴퓨터과학에서는 작업 분배, 강좌 배정, 네트워크 흐름 등에 곧장 적용됩니다.

12.6 채색 Coloring

그래프의 정점을 색칠할 때, 변으로 이어진 두 정점은 서로 다른 색이어야 한다는 제한을 둬 봅시다. 이런 식의 제약 만족 문제가 의외로 많은 응용을 갖습니다. 시험 시간표 짜기(과목이 정점, 시간 충돌이 변), 무선 주파수 할당(기지국이 정점, 간섭이 변), 컴파일러 레지스터 할당(변수가 정점, 동시 활성이 변) 같은 문제 모두 결국 그래프 채색이죠.

정의 12.6.1 (k-채색과 채색수)

그래프 \( G \)의 k-채색은 함수 \( c: V \to \{1, 2, \dots, k\} \)로서 모든 변 \( \{u, v\} \in E \)에 대해 \( c(u) \neq c(v) \)인 것이다. \( G \)에 \( k \)-채색이 존재하면 \( G \)는 \( k \)-채색 가능하다(\( k \)-colorable)고 한다. 그러한 \( k \) 가운데 가장 작은 값을 채색수(chromatic number) \( \chi(G) \)라 한다.

예제 12.6.2

\( \chi(K_n) = n \). 모든 정점이 모든 정점과 인접하니 색이 \( n \)개는 필요해요. \( \chi(C_n) \)은 \( n \)이 짝수면 2, 홀수면 3. \( \chi(K_{m,n}) = 2 \) — 한쪽은 색 1, 한쪽은 색 2면 끝. 이분 그래프는 정확히 2-채색 가능한 그래프와 같다는 사실이 곧 따라 나옵니다.

정리 12.6.3 (이분성 ↔ 2-채색성)

그래프 \( G \)가 이분 그래프인 것은 \( \chi(G) \le 2 \)인 것과 동치이며, 또한 \( G \)에 길이가 홀수인 사이클이 없는 것과도 동치이다.

채색수의 일반적 결정은 어렵습니다 — 정확히는 NP-완전. 하지만 평면 위에 변의 교차 없이 그릴 수 있는 그래프(평면 그래프)에 대해서는 이 세상에서 가장 유명한 그래프 정리가 답을 줍니다.

정리 12.6.4 (4색 정리, Four Color Theorem)

모든 평면 그래프는 4-채색 가능하다. 즉 \( \chi(G) \le 4 \).

노트 (역사)

이 정리는 1852년에 추측으로 제기되어 100년 넘게 풀리지 않다가 1976년 Appel과 Haken이 컴퓨터로 1936개의 경우를 따로따로 검증해 증명했습니다. "이게 진짜 증명이냐"는 철학적 논쟁을 일으킨 첫 사례 중 하나죠. 지금은 더 정돈된 컴퓨터 보조 증명들이 있지만, 사람이 머릿속에서만 검증할 수 있는 짧은 증명은 여전히 알려져 있지 않습니다.

12.7 단순 그래프의 워크 Walks in Simple Graphs

그래프 안에서 정점들 사이를 변을 타고 이동하는 길을 정확히 정의해 둡시다. 일상어 "경로"와 수학 용어가 미묘하게 다르므로 주의가 필요합니다.

정의 12.7.1 (워크, 패스, 사이클)

단순 그래프 \( G \)에서 워크(walk)는 정점과 변을 번갈아 적은 유한한 수열 \[ v_0, e_1, v_1, e_2, v_2, \dots, e_k, v_k \] 로서 각 \( e_i = \{v_{i-1}, v_i\} \in E \)인 것이다. 워크의 길이는 변의 개수 \( k \). 변이 모두 다르면 트레일(trail), 정점이 모두 다르면 패스(path)라 한다. \( k \ge 1 \)이고 \( v_0 = v_k \)이면 닫힌 워크(closed walk), 정점이 \( v_0 \)을 빼고 모두 다르고 \( k \ge 3 \)이면 사이클(cycle)이라 한다.

단순 그래프에서는 변이 한 쌍의 정점으로 결정되니, 변을 명시하지 않고 정점만 \( v_0, v_1, \dots, v_k \)로 적어도 워크가 잘 정의됩니다. 이 표기를 보통 더 자주 씁니다.

예제 12.7.2

\( C_5 \)에서 정점을 \( 1, 2, 3, 4, 5 \)라 두고 \( 1 \sim 2 \sim 3 \sim 4 \sim 5 \sim 1 \)이라 하자. \( 1, 2, 3, 2, 1 \)은 길이 4의 워크지만 트레일도 패스도 아니다(변 \( \{1,2\} \)가 두 번, 정점 1, 2도 반복). \( 1, 2, 3, 4 \)는 길이 3의 패스. \( 1, 2, 3, 4, 5, 1 \)은 길이 5의 사이클.

노트 (왜 이렇게 구분?)

증명에서 도구의 세기가 다르기 때문입니다. "두 정점 사이에 워크가 있다"보다 "패스가 있다"가 더 강한 결론이고, 보통은 워크에서 출발해 같은 정점을 두 번 방문하는 부분을 잘라내 패스로 줄이는 식으로 한 단계 강화합니다. 한국어 학생들이 처음에 가장 헷갈려하는 부분이니, 정의를 곁에 두고 예제로 손에 익히는 게 좋아요.

12.8 연결성 Connectivity

워크가 정의되면 자연스레 따라오는 개념이 연결성입니다. 두 정점이 같은 "덩어리"에 있는지 묻는 것이죠.

정의 12.8.1 (연결, 연결 성분)

단순 그래프 \( G \)에서 두 정점 \( u, v \)가 연결되어 있다(connected)는 것은 \( u \)에서 \( v \)로 가는 워크(동치적으로 패스)가 존재함을 뜻한다. 그래프 전체가 연결이라 함은 모든 정점 쌍이 연결되어 있다는 것이다. "연결되어 있다"는 동치 관계이며, 이 관계의 동치류 각각이 만들어내는 부분 그래프를 \( G \)의 연결 성분(connected component)이라 한다.

연결 성분은 그래프를 여러 덩어리로 깔끔하게 쪼개는 분할입니다. 그래프 알고리즘에서 가장 먼저 하는 전처리 중 하나가 BFS/DFS로 연결 성분을 모두 찾아 라벨링하는 일이죠. 시간 복잡도는 \( O(|V| + |E|) \).

예제 12.8.2

정점 6개 \( \{1,2,3,4,5,6\} \), 변이 \( \{1,2\}, \{2,3\}, \{4,5\} \)뿐인 그래프. 연결 성분은 \( \{1,2,3\} \), \( \{4,5\} \), \( \{6\} \) — 세 개. 정점 6은 변이 없는 고립점이지만 그 자체로 하나의 성분입니다.

노트 (변 개수의 하한)

연결 그래프는 변을 적어도 \( |V| - 1 \)개 가져야 합니다. 더 적으면 어떤 식으로 그어도 모든 정점을 한 덩어리로 묶을 수 없죠. 변이 정확히 \( |V| - 1 \)개인 연결 그래프 — 이게 곧 트리입니다(12.11에서 다시 만나요).

12.9 특수한 워크와 투어 Special Walks and Tours

그래프 이론은 18세기 쾨니히스베르크라는 도시의 다리 일곱 개에서 시작되었습니다. 시민들의 일요일 산책 퀴즈: "일곱 다리를 모두 정확히 한 번씩 건너서 출발지로 돌아올 수 있을까?" 1736년 오일러가 답했죠 — "할 수 없습니다." 그리고 그 이유를 일반화해 그래프 이론의 첫 정리가 탄생합니다.

정의 12.9.1 (오일러 회로, 해밀턴 회로)

그래프 \( G \)의 오일러 트레일은 모든 변을 정확히 한 번씩 사용하는 트레일이다. 닫힌 오일러 트레일을 오일러 회로(Eulerian circuit)라 한다. 한편 모든 정점을 정확히 한 번씩 방문하는 사이클을 해밀턴 회로(Hamiltonian cycle)라 한다.

오일러 회로의 특징은 변을 빠짐없이 한 번씩, 해밀턴 회로의 특징은 정점을 빠짐없이 한 번씩 — 한 글자 차이지만 난이도가 천양지차입니다.

정리 12.9.2 (오일러 정리)

연결 그래프 \( G \)에 오일러 회로가 존재할 필요충분조건은 모든 정점의 차수가 짝수인 것이다. 오일러 트레일(닫혀 있지 않아도 됨)이 존재할 필요충분조건은 차수가 홀수인 정점이 0개이거나 정확히 2개인 것이다.

증명 (스케치)

(⇒) 회로를 따라가면, 정점에 들어올 때마다 1개의 새 변, 나갈 때마다 1개의 새 변을 쓰니까 각 정점의 차수는 짝수가 되어야 한다.

(⇐) 귀납법. 임의의 정점에서 출발해 갈 수 있는 한 변을 골라 따라간다(쓴 변은 그래프에서 제거). 차수가 짝수인 그래프에서는 출발점에 돌아올 때까지 막히지 않는다. 돌아왔는데 변이 남아 있으면, 회로 위 어떤 정점에서 남은 변이 출발하므로 그 정점에서 다시 보조 회로를 만들고 둘을 합친다. 변이 유한이므로 끝난다.

쾨니히스베르크 다리는 네 정점(섬·강안)의 차수가 각각 5, 3, 3, 3으로 모두 홀수, 홀수 차수 정점이 4개이므로 오일러 회로도 트레일도 불가능. 오일러는 이 단순한 기준으로 산책 문제에 종지부를 찍었습니다.

노트 (해밀턴 회로의 비대칭성)

해밀턴 회로 존재 판정은 NP-완전. 깔끔한 필요충분조건은 알려져 있지 않고, 충분조건들(예: 디락의 정리 — 모든 정점 차수 \( \ge n/2 \))이 있을 뿐입니다. 변의 문제(오일러)와 정점의 문제(해밀턴)가 본질적으로 다른 복잡도 클래스에 속한다는 사실은 그래프 이론의 가장 흥미로운 비대칭 중 하나예요.

12.10 k-연결 그래프 k-connected Graphs

연결 그래프는 한 덩어리지만, 정점 하나만 빼면 두 덩어리로 쪼개질 수도 있죠. 이런 "약한 연결"과 "튼튼한 연결"을 구분하기 위한 개념이 \( k \)-연결성입니다.

정의 12.10.1 (k-연결)

정점 수가 \( k+1 \) 이상인 단순 그래프 \( G \)가 \( k \)-연결(\( k \)-connected)이라 함은, 어떤 \( k-1 \)개 이하의 정점을 제거해도 남은 그래프가 여전히 연결인 것이다. 동치적으로, 임의의 두 정점 \( u, v \) 사이에 정점이 서로 겹치지 않는 \( k \)개의 패스가 존재한다(멩거의 정리).

1-연결은 보통의 연결과 같습니다. 2-연결 이상은 흔히 "안전한 네트워크"와 관련됩니다. 라우터 한 대가 죽어도 인터넷이 죽지 않으려면 라우팅 그래프가 2-연결이어야 하죠. 데이터센터 토폴로지나 항공 노선망 설계에서 \( k \)-연결성은 핵심 지표입니다.

예제 12.10.2

\( C_n \) (\( n \ge 3 \))은 정확히 2-연결이다. 어떤 정점 하나만 빼도 \( P_{n-1} \)이 남아 연결이지만, 잘 고른 두 정점을 빼면 두 조각으로 쪼개진다. 한편 \( K_n \)은 \( (n-1) \)-연결이며, 그래프가 가질 수 있는 최대 연결도가 \( n-1 \)임을 보여 준다. 트리는 항상 잎 노드를 빼면 연결이지만 내부 노드를 빼면 쪼개지므로 1-연결이지만 2-연결은 아니다.

정리 12.10.3 (멩거, Menger)

그래프 \( G \)의 두 정점 \( u, v \) 사이에 정점이 서로 겹치지 않는 패스의 최대 개수는, \( u \)와 \( v \) 사이의 모든 패스를 끊기 위해 제거해야 하는 정점의 최소 개수와 같다.

멩거의 정리는 그래프 이론의 모든 "최소 컷 = 최대 흐름" 류 정리들의 원형이며, 알고리즘적으로는 네트워크 흐름으로 환원해 효율적으로 풀 수 있습니다.

12.11 숲과 트리 Forests & Trees

마지막으로 그래프 이론에서 가장 깔끔한 가족, 트리를 만나봅시다. 컴퓨터과학 전체의 자료구조 절반을 떠받치고 있는 구조죠.

정의 12.11.1 (트리, 숲)

사이클이 없는 그래프를 (forest)이라 하고, 연결된 숲을 트리(tree)라 한다. 차수가 1인 정점은 트리의 (leaf)이다.

트리는 동치인 정의가 여러 개여서, 어떤 게 가장 자연스럽냐는 책마다 다릅니다. 다음 정리가 핵심입니다.

정리 12.11.2 (트리의 다섯 동치 정의)

정점 수 \( n \ge 1 \)의 그래프 \( G \)에 대해 다음 다섯 명제는 모두 동치이다:

  1. \( G \)는 트리이다(연결이고 사이클이 없다).
  2. \( G \)는 연결이고 변의 개수가 \( n - 1 \)이다.
  3. \( G \)는 사이클이 없고 변의 개수가 \( n - 1 \)이다.
  4. \( G \)에서 임의의 두 정점 사이에 정확히 하나의 패스가 존재한다.
  5. \( G \)는 연결이지만, 어떤 변을 제거해도 연결성이 깨진다(최소 연결).

증명 (스케치)

(1)⇒(2): 연결이고 사이클이 없으면 변 개수 = 정점 개수 − 1을 정점 수에 대한 귀납법으로 보임. 잎이 항상 존재함을 이용해 잎을 떼어내며 줄이면 됩니다.

(2)⇒(3): 연결이면 어쨌든 사이클이 있으면 변을 하나 빼도 연결이라 변 개수가 \( n-1 \)인 연결 그래프에 사이클이 있다면 모순.

(3)⇒(4): 사이클이 없다면 두 패스가 있을 때 그 둘을 합치면 사이클이 만들어져 모순. 변 개수 \( n-1 \) + 사이클 없음 ⇒ 연결도 함의.

(4)⇒(5): 패스가 유일하면 그 패스 위 어느 변을 빼도 두 정점이 끊어진다.

(5)⇒(1): 연결이고 변 하나만 빼도 끊긴다면 사이클이 있을 수 없다(사이클이 있으면 그 위 변 하나는 빼도 됨).

예제 12.11.3

회사의 조직도, 파일 시스템, HTML DOM, 의사 결정 트리, 이진 검색 트리, 허프만 코딩 트리, 게임의 가능한 수의 펼침 — 모두 트리. 정점 \( n \)개짜리 트리의 변은 \( n - 1 \)개로 작지만, 표현하는 정보의 양은 어마어마하죠. 그래프 알고리즘의 많은 부분이 "그래프에서 트리를 찾기"(예: 최소 신장 트리, BFS/DFS 트리)로 환원됩니다.

노트 (왜 트리가 그렇게 자주 나오나)

트리는 "정점을 다 잇는 가장 적은 변"이라는 미니멀리즘의 끝입니다. 사이클이 없으니 분석이 단순하고, 패스가 유일하니 알고리즘이 결정적이며, 변이 \( n-1 \)개뿐이니 메모리도 작습니다. 컴퓨터과학 전체에서 가장 사랑받는 그래프인 데에는 다 이유가 있어요. 다음 챕터부터는 이 트리들을 무대 삼아 더 정교한 그래프 분석을 이어가게 됩니다.

PART II — 구조

13 평면 그래프 Planar Graphs

지하철 노선도, 회로 기판, 다이아몬드의 결정 구조 — 평면 그래프는 어디에나 있어요. 종이 위에 선이 서로 교차하지 않게 그릴 수 있는 그래프, 그게 바로 이 챕터의 주인공입니다. 단순해 보이는 이 조건이 오일러 공식, 4색 정리, 정다면체 분류 같은 놀라운 결과들로 이어진다는 게 신기하죠. 이번 챕터에서는 평면 그래프의 정의부터 시작해서, 간선 수의 한계를 구하고, \(K_5\)와 \(K_{3,3}\)이 왜 평면에 그릴 수 없는지 증명하고, 마지막엔 정다면체가 왜 정확히 5개뿐인지까지 살펴봅니다.

13.1 평면에 그래프 그리기 Drawing Graphs in the Plane

그래프를 종이에 그릴 때, 우리는 정점을 점으로 찍고 간선을 곡선으로 잇습니다. 그런데 간선들이 서로 가로지르지 않게 그릴 수 있을까요? 어떤 그래프는 손쉽게 가능하지만, 어떤 그래프는 아무리 돌려봐도 어딘가는 꼭 교차합니다. 이 차이를 수학적으로 다루는 게 바로 평면 그래프 이론이에요.

가장 유명한 도입 문제가 있습니다. 바로 세 집-세 우물 문제(three utilities puzzle)예요. 세 채의 집이 나란히 있고, 그 앞에 세 개의 우물(가스, 물, 전기라고 해도 좋아요)이 있습니다. 모든 집은 모든 우물에 연결되어야 하는데, 파이프들이 서로 교차하면 안 된다는 조건이 붙어요. 자, 종이 위에서 이걸 해낼 수 있을까요?

노트

한번 직접 그려보세요. 8개의 연결까진 어렵지 않게 됩니다. 그런데 마지막 9번째 연결에서 항상 막혀요. 우연이 아니라, 수학적으로 불가능하다는 게 곧 증명될 겁니다.

이 문제는 그래프 언어로 옮기면 \(K_{3,3}\), 즉 양쪽에 정점이 3개씩 있는 완전이분그래프를 평면에 교차 없이 그릴 수 있느냐는 질문이 됩니다. 결론부터 말하면, 답은 "안 된다"입니다. 그리고 왜 안 되는지를 증명하는 게 이 챕터의 핵심 도구가 돼요.

비슷하게 \(K_5\) — 정점 5개가 모두 서로 연결된 완전그래프 — 도 평면에 그릴 수 없습니다. 이 두 그래프, \(K_5\)와 \(K_{3,3}\)은 "평면 그래프가 아닌 가장 작은 두 가지" 같은 위치를 차지해요. 나중에 쿠라토프스키 정리에서 더 멋진 의미를 갖게 됩니다.

예제 13.1.1

\(K_4\)는 어떨까요? 정점 4개를 모두 연결한 완전그래프입니다. 일단 정사각형으로 그리면 두 대각선이 교차하지만, 한 정점을 가운데로 옮기고 나머지 셋을 삼각형으로 두르면 교차 없이 그릴 수 있어요. 따라서 \(K_4\)는 평면 그래프입니다.

13.2 평면 그래프의 정의 Definitions of Planar Graphs

이제 정의를 엄밀하게 적어봅시다. 직관은 충분히 쌓였으니까요.

정의 13.2.1 (평면 그래프)

그래프 \(G\)가 평면 그래프(planar graph)라는 것은, 평면 위에 \(G\)의 정점들을 점으로, 간선들을 두 끝 정점을 잇는 곡선으로 그릴 수 있되 서로 다른 두 간선이 끝점이 아닌 곳에서 절대 교차하지 않도록 그릴 수 있다는 뜻입니다.

주의할 점이 있어요. 평면 그래프인 것과 평면에 "교차 없이 그려진" 것은 약간 다릅니다. 같은 그래프를 어떤 식으로 그리느냐에 따라 교차가 생길 수도 있고 없을 수도 있어요. 평면 그래프란 "교차 없이 그릴 수 있는 방법이 적어도 하나 존재하는" 그래프를 말합니다.

평면 위에 교차 없이 그려진 그래프는 평면을 여러 영역으로 나눕니다. 이 각 영역을 (face)이라고 불러요.

정의 13.2.2 (면)

평면에 교차 없이 그려진 그래프의 은 그래프의 간선들로 둘러싸인 평면의 연결된 영역입니다. 그래프의 바깥쪽 무한히 펼쳐진 영역도 하나의 면으로 셉니다(이를 외부면이라고 부릅니다).

예제 13.2.3

삼각형(\(K_3\))을 평면에 그리면 면이 두 개 있습니다. 삼각형 안쪽 영역 하나, 그리고 삼각형 바깥의 무한 영역 하나. \(V=3,\ E=3,\ F=2\)예요.

정사각형 모양 \(C_4\)도 마찬가지로 \(V=4,\ E=4,\ F=2\). 안쪽과 바깥쪽.

그런데 \(K_4\)를 평면에 잘 그리면 (한 정점을 삼각형 안에 넣어서) 작은 삼각형 영역 3개 + 바깥 무한 영역 1개 = \(F=4\). \(V=4,\ E=6,\ F=4\)네요.

노트

외부면을 빼먹는 실수가 정말 흔합니다. "내가 둘러싼 영역만 면 아닌가?" 싶지만, 수학적으로는 그래프가 둘러싸지 못한 무한히 큰 바깥쪽도 똑같이 한 영역으로 취급해요. 면을 셀 때 항상 +1을 잊지 마세요.

13.3 오일러 공식 Euler's Formula

위 예제들을 다시 봅시다. \(V-E+F\)를 계산해보세요.

  • \(K_3\): \(3-3+2=2\)
  • \(C_4\): \(4-4+2=2\)
  • \(K_4\): \(4-6+4=2\)

전부 \(2\)예요. 우연이 아닙니다.

정리 13.3.1 (오일러 공식)

연결된 평면 그래프를 평면에 교차 없이 그렸을 때, 정점 수 \(V\), 간선 수 \(E\), 면 수 \(F\)는 항상 다음을 만족합니다. \[ V - E + F = 2. \]

증명 (간선 수에 대한 귀납)

간선 수 \(E\)에 대한 귀납으로 보입니다.

기저: \(E=0\)이면 연결그래프이므로 \(V=1\), 면은 외부면 하나뿐이라 \(F=1\). \(1-0+1=2\). 성립합니다.

귀납 단계: \(E\geq 1\)일 때, 두 가지 경우로 나눕니다.

(i) 그래프에 사이클이 있으면, 어떤 사이클 위의 간선 \(e\)를 골라 제거합시다. \(e\)는 두 면(사이클 안쪽과 바깥쪽)의 경계였으므로, 제거하면 두 면이 하나로 합쳐져 면 수가 1 줄어들어요. 정점 수는 그대로, 간선 수는 1 줄어들고 그래프는 여전히 연결입니다. 귀납 가정에 의해 \(V-(E-1)+(F-1)=2\), 즉 \(V-E+F=2\). 성립.

(ii) 그래프에 사이클이 없으면 그것은 트리입니다. 트리에서는 잎(degree 1 정점)을 하나 떼어냅시다. 정점과 간선이 각각 1씩 줄고, 면 수는 그대로 1입니다(트리는 사이클이 없으니 외부면만 존재). 귀납 가정에 의해 \((V-1)-(E-1)+F=2\), 즉 \(V-E+F=2\). 성립.

오일러 공식은 단순해 보이지만 굉장히 강력합니다. \(V, E\) 둘 중 하나만 알아도 면 수에 제약이 생기고, 곧 보겠지만 평면 그래프의 간선 수에 상한을 강제하기까지 합니다.

13.4 평면 그래프 간선 수 한계 Bounding the Number of Edges in a Planar Graph

평면 그래프는 정점 수에 비해 너무 많은 간선을 가질 수 없습니다. 직관적으로, 정점이 \(V\)개라도 간선이 너무 많으면 어느 순간 교차하지 않고는 그릴 수가 없거든요. 이걸 수식으로 깔끔하게 잡아봅시다.

핵심 아이디어는 면-간선 이중 계산(double counting)입니다. 각 면의 경계 길이(둘러싼 간선 수)를 모두 합하면 어떻게 될까요? 모든 간선은 양쪽에 면이 하나씩 붙어 있으니까(같은 면이 양쪽일 수도 있지만 그래도 두 번 카운트됨), 이 합은 정확히 \(2E\)와 같습니다.

정리 13.4.1 (간선 수 상한)

\(V\geq 3\)인 단순 연결 평면 그래프에서 \[ E \leq 3V - 6. \] 또한 그래프가 이분(bipartite)이면 더 강하게 \[ E \leq 2V - 4. \]

증명

단순 그래프이고 \(V\geq 3\)이라면 어떤 면도 길이 1이나 2의 경계를 가질 수 없어요(루프나 다중 간선이 없으니까). 따라서 모든 면의 경계 길이는 최소 \(3\)입니다. 면이 \(F\)개일 때 경계 길이의 총합은 적어도 \(3F\)이고, 이중 계산에서 이 합은 \(2E\)이므로 \[ 3F \leq 2E \quad\Rightarrow\quad F \leq \frac{2E}{3}. \] 오일러 공식 \(V-E+F=2\)에서 \(F=2-V+E\)이므로 \[ 2 - V + E \leq \frac{2E}{3} \quad\Rightarrow\quad E \leq 3V-6. \]

이분 그래프의 경우, 짝수 길이 사이클만 가지므로 모든 면의 경계 길이는 최소 \(4\)입니다. 같은 논리로 \(4F\leq 2E\), 즉 \(F\leq E/2\). 오일러 공식과 결합하면 \[ 2-V+E \leq \frac{E}{2} \quad\Rightarrow\quad E \leq 2V-4. \]

예제 13.4.2

정점이 10개인 평면 그래프는 간선이 최대 몇 개? \(3\cdot 10-6=24\)개. 그런데 이 그래프가 이분이라면? 최대 \(2\cdot 10-4=16\)개로 더 줄어요.

노트

이 부등식의 진짜 위력은 "평면이 아님"을 증명할 때 나옵니다. 어떤 그래프가 \(E>3V-6\)이면, 그건 평면 그래프가 될 수 없어요. 대우(contrapositive)로 쓰는 게 핵심이에요.

13.5 \(K_5\)와 \(K_{3,3}\)로의 회귀 Returning to K5 and K3,3

13.1에서 미뤄둔 약속을 갚을 시간이에요. \(K_5\)와 \(K_{3,3}\) 둘 다 평면 그래프가 아니라는 사실을 13.4의 부등식으로 정확히 증명할 수 있습니다.

정리 13.5.1

\(K_5\)는 평면 그래프가 아닙니다.

증명

\(K_5\)는 정점이 \(V=5\)개이고 모든 쌍이 간선으로 연결되어 있으니 간선이 \(E=\binom{5}{2}=10\)개입니다. 만약 \(K_5\)가 평면 그래프라면, \(V\geq 3\)이므로 \(E\leq 3V-6\)이 성립해야 하는데 \[ 3V-6 = 3\cdot 5 - 6 = 9. \] 그러나 \(E=10 > 9\)이므로 모순. 따라서 \(K_5\)는 평면 그래프가 아닙니다.

정리 13.5.2

\(K_{3,3}\)은 평면 그래프가 아닙니다.

증명

\(K_{3,3}\)은 양쪽에 정점이 3개씩 있는 완전이분그래프이므로 \(V=6\), \(E=3\cdot 3=9\)입니다. 또한 이분 그래프죠. 만약 평면이라면 이분 평면에 대한 부등식 \(E\leq 2V-4\)이 성립해야 하는데 \[ 2V-4 = 2\cdot 6 - 4 = 8. \] 그런데 \(E=9 > 8\). 모순입니다. 따라서 \(K_{3,3}\)은 평면 그래프가 아니에요.

노트

\(K_{3,3}\)에 일반 부등식 \(E\leq 3V-6=12\)를 그대로 쓰면 \(9\leq 12\)라 모순이 안 나옵니다. 그래서 이분이라는 추가 정보를 써서 \(2V-4\)라는 더 빡빡한 부등식을 적용해야 모순을 만들 수 있어요. 이게 "이분 그래프엔 더 좋은 한계가 있다"의 진짜 이유입니다.

드디어 세 집-세 우물 퍼즐의 답이 나왔어요. 절대로 못 그립니다. 종이에서 못 그릴 뿐 아니라, 평면이라는 공간 자체에서 불가능합니다(도넛 표면 같은 데서는 가능하답니다, 흥미롭게도).

13.6 평면 그래프의 채색 Coloring Planar Graphs

지도를 색칠할 때, 인접한 나라(국경을 맞댄 나라)에 같은 색을 쓰지 않으려면 색이 몇 개 필요할까요? 각 나라를 정점으로, 인접한 나라끼리 간선으로 잇는 그래프를 만들면, 이 그래프는 자연스럽게 평면 그래프가 됩니다. 따라서 지도 색칠 문제는 곧 평면 그래프의 채색수(chromatic number) 문제예요.

정리 13.6.1 (5색 정리)

모든 평면 그래프는 5색으로 채색 가능합니다. 즉 평면 그래프의 채색수는 \(\chi(G)\leq 5\).

증명 스케치

먼저 보조 사실: 모든 평면 그래프에는 차수가 \(5\) 이하인 정점이 적어도 하나 있습니다. 왜냐하면 만약 모든 정점이 차수 \(\geq 6\)이라면 \(2E=\sum_v \deg(v)\geq 6V\), 즉 \(E\geq 3V\)인데 평면 그래프에선 \(E\leq 3V-6 < 3V\)이라 모순이거든요.

이제 정점 수 \(V\)에 대한 강귀납을 사용합니다. \(V\leq 5\)이면 자명. \(V>5\)일 때, 차수 \(\leq 5\)인 정점 \(v\)를 잡고, \(v\)를 일단 떼어내요. 남은 그래프는 정점 수가 적으니 귀납 가정에 의해 5색 채색이 가능합니다.

이제 \(v\)에 색을 줘야 합니다. \(v\)의 이웃은 최대 5개. 만약 그들이 5색 중 하나라도 안 쓴 색이 있다면 그 색을 \(v\)에 칠하면 끝. 만약 5명이 5색을 모두 정확히 다르게 쓰고 있다면? 이 경우엔 켐페 사슬(Kempe chain) 논증을 써서 두 이웃의 색을 교묘하게 바꿔치기해 한 색을 비워낼 수 있습니다(자세한 건 좀 더 정교한 케이스 분석이 필요해요).

정리 13.6.2 (4색 정리, Appel-Haken 1976)

모든 평면 그래프는 4색으로 채색 가능합니다.

노트

4색 정리는 100년 넘게 미해결 난제였다가 1976년에 Appel과 Haken이 컴퓨터의 도움으로 증명했어요. 약 1500개의 환원 가능한 구성을 컴퓨터로 일일이 검증한 증명이라, 처음엔 "이걸 진짜 증명이라 부를 수 있나?" 논쟁이 있었답니다. 지금은 받아들여진 정리지만, 이 챕터에선 손으로 증명할 수 있는 5색 정리까지만 다룹니다.

13.7 다면체 분류 Classifying Polyhedra

오일러 공식의 가장 우아한 응용 중 하나는 정다면체(Platonic solid)가 정확히 5개뿐이라는 사실의 증명입니다. 정다면체란 모든 면이 합동인 정다각형이고 모든 꼭짓점이 동일한 모양으로 만나는 볼록다면체예요.

왜 평면 그래프가 다면체랑 관련이 있을까요? 볼록다면체를 잡고 그 한 면을 풍선 늘이듯이 평면 위로 펼치면, 다면체의 정점-간선 구조가 평면 그래프가 됩니다. 그러면 오일러 공식 \(V-E+F=2\)를 그대로 적용할 수 있어요(여기서 \(F\)는 다면체의 면 수와 일치하고, 외부면이 곧 펼친 그 면에 해당합니다).

각 면이 \(p\)각형이고 각 꼭짓점에 \(q\)개의 면이 모인다고 합시다. 그러면:

  • 면 수 × 면당 변 수는 간선을 두 번 셈: \(pF = 2E\), 즉 \(F=2E/p\).
  • 꼭짓점 수 × 꼭짓점당 모이는 면(=간선 수)은 간선을 두 번 셈: \(qV = 2E\), 즉 \(V=2E/q\).

오일러 공식에 대입하면 \[ \frac{2E}{q} - E + \frac{2E}{p} = 2 \quad\Rightarrow\quad \frac{1}{p}+\frac{1}{q} = \frac{1}{2}+\frac{1}{E}. \] \(E>0\)이므로 우변 \(>1/2\), 즉 \[ \frac{1}{p}+\frac{1}{q} > \frac{1}{2}. \] 또한 \(p\geq 3\)(다각형이니), \(q\geq 3\)(꼭짓점에 최소 3면 모임).

이 부등식 \(\frac{1}{p}+\frac{1}{q}>\frac{1}{2}\)에 \(p,q\geq 3\)인 정수해를 모두 찾아봅시다.

  • \(p=3\)이면 \(\frac{1}{q}>\frac{1}{6}\), 즉 \(q<6\). 가능한 \(q=3,4,5\).
  • \(p=4\)이면 \(\frac{1}{q}>\frac{1}{4}\), 즉 \(q<4\). 가능한 \(q=3\).
  • \(p=5\)이면 \(\frac{1}{q}>\frac{3}{10}\), 즉 \(q\leq 3\). 가능한 \(q=3\).
  • \(p\geq 6\)이면 \(\frac{1}{p}+\frac{1}{q}\leq \frac{1}{6}+\frac{1}{3}=\frac{1}{2}\)라 부등식 위반. 불가능.

따라서 가능한 \((p,q)\)는 정확히 5쌍: \((3,3),(3,4),(3,5),(4,3),(5,3)\). 이 다섯이 정사면체부터 정이십면체까지 다섯 정다면체에 대응합니다.

이름\(p\)\(q\)\(V\)\(E\)\(F\)
정사면체 (Tetrahedron)33464
정육면체 (Cube)438126
정팔면체 (Octahedron)346128
정십이면체 (Dodecahedron)53203012
정이십면체 (Icosahedron)35123020

각 행의 \(V-E+F\)를 계산해보면 모두 \(2\)예요. 오일러 공식이 다면체의 세계에서도 그대로 살아있다는 게 정말 멋지죠.

노트

플라톤은 이 다섯 다면체를 4원소(불, 흙, 공기, 물)와 우주 자체에 대응시켰어요. 수학적으로는 그저 부등식 \(1/p+1/q>1/2\)의 정수해가 다섯이라는 단순한 사실인데, 이 단순함이 도리어 우주의 어떤 미감을 자아내는 것 같습니다.

13.8 평면 그래프의 또 다른 특성 Another Characterization for Planar Graphs

지금까지 본 부등식 \(E\leq 3V-6\)은 평면 그래프가 되기 위한 필요조건이지만 충분조건은 아닙니다. 즉, 부등식을 만족하는데도 평면이 아닌 그래프가 있을 수 있어요. 그러면 평면 그래프를 그래프 자체의 구조만으로 완전히 특징지을 방법이 있을까요?

놀랍게도 답은 "예"입니다. 그것도 \(K_5\)와 \(K_{3,3}\)을 다시 만나면서요.

정리 13.8.1 (쿠라토프스키 정리, 1930)

그래프 \(G\)가 평면 그래프인 것은 \(G\)가 \(K_5\) 또는 \(K_{3,3}\)의 분할(subdivision)을 부분그래프로 포함하지 않을 필요충분조건입니다.

여기서 분할이란 어떤 간선의 중간에 새로운 차수-2 정점을 끼워넣는 연산을 반복해서 얻는 그래프를 말합니다. 직관적으로는 간선을 "여러 토막으로 잘라낸" 그래프예요. 본질적으로는 같은 그래프인 셈이죠.

이 정리의 의미는 깊습니다. 평면이 아닌 모든 그래프는 그 안에 어떤 식으로든 \(K_5\)나 \(K_{3,3}\)을 "숨기고" 있다는 말이거든요. 이 둘이 비평면성의 근원적인 두 가지 패턴이라는 거예요.

노트

비슷한 정리로 와그너 정리(Wagner's theorem)가 있어요. 이 정리는 "분할" 대신 "마이너(minor)"라는 더 일반적인 연산을 써서 같은 결과를 말합니다: \(G\)가 평면이려면 \(K_5\)와 \(K_{3,3}\)을 마이너로 가지지 않아야 한다는 거죠. 이게 더 나아가면 그래프 마이너 이론(로버트슨-시모어 이론)이라는 거대한 분야로 이어집니다.

평면 그래프의 인식 자체는 효율적으로 풀 수 있는 문제이기도 합니다. 1974년 호프크로프트와 타잔이 \(O(V)\) 시간에 평면성을 판정하는 알고리즘을 제시했어요. 그래프 이론과 알고리즘이 만나는 멋진 지점이죠.

이 챕터를 마치면서, 평면 그래프가 단지 "예쁜 그림"의 문제가 아니라는 걸 다시 강조하고 싶어요. 회로 기판 설계에서는 평면성이 곧 단일 층에 인쇄 가능한지를 결정하고, 컴퓨터 그래픽에서는 평면 메시 분해가 텍스처 매핑의 기반이 됩니다. 단순한 정의에서 출발한 이론이 이렇게 풍부한 응용으로 뻗어나간다는 점이, 이산수학을 공부하는 즐거움 중 하나예요.

PART III — 세기

14 합과 점근 Sums and Asymptotics

합을 정확히 계산할 수 있으면 좋지만, 현실의 합들은 닫힌 꼴(closed form)이 잘 안 나옵니다. 그럴 땐 근사(approximate)합니다. 이번 장에서는 등비급수 같은 익숙한 합부터 시작해 거듭제곱의 합, 적분으로의 근사, 그리고 발산하는 조화수까지 쭉 훑어봅니다. 그 와중에 "책을 모서리 위로 무한히 매달 수 있다"는 직관에 어긋나는 결과 하나를 만나고, 마지막엔 컴퓨터과학 수업 내내 따라다니는 점근 표기법(O, Ω, Θ, o, ω)을 정리합니다. 알고리즘 수업의 절반은 결국 이 표기법으로 이야기되니까요.

14.1 연금의 가치 The Value of an Annuity

합 이야기를 금융에서 시작하는 건 좀 의외일 수 있는데, 사실 등비급수 공식이 가장 자연스럽게 등장하는 무대 중 하나가 연금(annuity)입니다. 시나리오는 단순해요. 매년 \( m \)원씩 \( n \)년 동안 받기로 한 계약이 있다고 해 봅시다. 이 계약의 "지금 가치"는 얼마일까요?

핵심은 돈에는 시간 가치가 있다는 점입니다. 1년 뒤 받는 1만 원은 오늘 받는 1만 원과 같지 않아요. 오늘 1만 원이 있으면 은행에 넣어 이자를 받을 수 있으니까요. 이자율을 연 \( p \)라 하면, 오늘 1원은 1년 뒤 \( 1+p \)원이 되고, 거꾸로 1년 뒤 1원은 오늘 \( \frac{1}{1+p} \)원의 가치만큼만 됩니다. \( r = \frac{1}{1+p} \)라 두면 \( k \)년 뒤 1원의 현재 가치는 \( r^k \)입니다.

정의 14.1.1 (연금의 현재 가치)

매년 \( m \)원을 1년 차부터 \( n \)년 차까지 받는 연금의 현재 가치(present value)는 \[ V \;=\; \sum_{k=1}^{n} m\, r^k \;=\; m\,(r + r^2 + r^3 + \cdots + r^n), \] 여기서 \( r = 1/(1+p) \)이고 \( p \)는 연이자율이다.

이 합을 손으로 닫아 봅시다. 등비급수의 정석 트릭은 "원래 합과 \( r \)배 한 합을 빼는" 거예요.

정리 14.1.2 (유한 등비급수)

\( r \neq 1 \)이면 \[ S_n \;=\; \sum_{k=0}^{n} r^k \;=\; 1 + r + r^2 + \cdots + r^n \;=\; \frac{1 - r^{n+1}}{1 - r}. \] 특히 \( |r| < 1 \)이면 \( n \to \infty \)일 때 \[ \sum_{k=0}^{\infty} r^k \;=\; \frac{1}{1-r}. \]

증명 (한 줄짜리 트릭)

\( S_n - r S_n = (1 + r + \cdots + r^n) - (r + r^2 + \cdots + r^{n+1}) = 1 - r^{n+1} \). \( (1-r) \)로 나누면 끝.

그래서 연금의 현재 가치는

\[ V \;=\; m \cdot \frac{r(1 - r^n)}{1 - r}. \]

예를 들어 매년 100만 원씩 30년 동안 받기로 했고 이자율이 5%면 \( r = 1/1.05 \approx 0.952 \), 계산기를 한 번 두드리면 \( V \approx 1{,}537 \)만 원 정도가 나옵니다. 명목상 받는 총액은 3000만 원인데, "지금 한 번에" 받는다면 그 절반밖에 안 된다는 거예요. 시간이 끼면 돈이 가벼워집니다.

노트 — 영원히 받는 연금

특수 케이스로, 매년 \( m \)원을 영원히 받는 영구 연금(perpetuity)은 \( n \to \infty \)이고 \( |r| < 1 \)이므로 \( V = mr/(1-r) = m/p \)입니다. 이자율이 5%면 매년 100만 원짜리 영구 연금의 현재 가치는 단지 \( 100/0.05 = 2000 \)만 원. "영원히 100만 원 받기"가 2000만 원이라는 게 처음엔 작아 보이지만, 시간 할인의 위력을 보여주는 숫자죠.

14.2 거듭제곱의 합 Sums of Powers

등비급수 다음으로 자주 만나는 합은 거듭제곱의 합입니다. 가장 어린 사촌은 \( 1 + 2 + \cdots + n \)이에요.

정리 14.2.1 (1차의 합)

\[ \sum_{k=1}^{n} k \;=\; \frac{n(n+1)}{2}. \]

증명 스케치 (가우스의 학교 일화)

합을 \( S \)라 두고 같은 합을 거꾸로 적습니다. \[ S = 1 + 2 + \cdots + n, \qquad S = n + (n-1) + \cdots + 1. \] 두 식을 더하면 \( 2S \)가 \( n \)개의 \( (n+1) \)이 되어 \( 2S = n(n+1) \).

제곱의 합은 살짝 더 복잡한데, 결과는 여전히 깔끔합니다.

정리 14.2.2 (제곱의 합)

\[ \sum_{k=1}^{n} k^2 \;=\; \frac{n(n+1)(2n+1)}{6}. \]

증명은 귀납법이 정석이고(5장), 좀 더 우아하게는 \( (k+1)^3 - k^3 \)의 텔레스코핑 합을 이용해 유도할 수도 있습니다. 핵심 아이디어만 말하면, \( (k+1)^3 - k^3 = 3k^2 + 3k + 1 \)이고 양변을 \( k = 1 \)부터 \( n \)까지 더하면 좌변은 망원경(telescope)으로 \( (n+1)^3 - 1 \)이 됩니다. 우변에서 \( \sum k \)는 이미 알고 있으니 \( \sum k^2 \)을 풀어낼 수 있어요.

일반화하면, 임의의 양의 정수 \( d \)에 대해

\[ \sum_{k=1}^{n} k^d \;=\; \frac{n^{d+1}}{d+1} \;+\; \text{(낮은 차수 항들)}. \]

즉, "0부터 \( n \)까지 \( k^d \)를 적분한 것"인 \( n^{d+1}/(d+1) \)이 주된 항입니다. 이건 우연이 아니라 합이 적분의 이산판이라는 깊은 사실의 단서인데, 다음 절에서 이걸 진짜로 써먹습니다.

예제 14.2.3

한 알고리즘이 입력 크기 \( n \)에서 정확히 \( \sum_{k=1}^{n} k = n(n+1)/2 \)번의 비교를 수행한다고 합시다. 그러면 큰 \( n \)에서 이 알고리즘의 비용은 \( n^2/2 \)에 가깝고, "n²급" 즉 이차 시간 알고리즘이라고 부릅니다. 점근적 동치는 14.7절에서 \( \Theta(n^2) \)로 정확히 표현하게 돼요.

14.3 합의 근사 Approximating Sums

닫힌 꼴이 없는 합은 어떻게 다룰까요? 답은 단순합니다 — 적분으로 갈아타는 거예요. 함수 \( f \)가 양수이고 단조증가(monotonic increasing)면, \( k \)에서 \( k+1 \) 사이의 적분 \( \int_k^{k+1} f(x)\,dx \)는 그 구간에서 \( f \)의 어떤 값과 그 다음 값 사이에 갇혀요. 이걸 박스로 그려 보면 다음과 같은 부등식이 즉시 나옵니다.

정리 14.3.1 (적분 비교 부등식)

\( f \)가 \( [1, n+1] \)에서 양수이고 단조증가하면 \[ \int_{1}^{n+1} f(x)\,dx \;\le\; \sum_{k=1}^{n} f(k+1) \;\text{... 등등.} \] 더 깔끔히 표현하면, 단조증가 \( f \)에 대해 \[ \int_{0}^{n} f(x)\,dx \;\le\; \sum_{k=1}^{n} f(k) \;\le\; \int_{1}^{n+1} f(x)\,dx, \] 단조감소면 부등호 방향이 뒤집힌다.

그림 없이 글로 설명하면 이렇습니다. \( f \)가 증가함수일 때, 폭이 1이고 높이가 \( f(k) \)인 직사각형은 \( [k-1, k] \) 위의 적분을 덮고, \( [k, k+1] \) 위의 적분에는 못 미칩니다. 그래서 직사각형 합 \( \sum f(k) \)는 두 적분 사이에 끼이게 돼요. 단조감소면 그 반대.

예제 14.3.2 (\( \sqrt{k} \)의 합)

\( S = \sum_{k=1}^{n} \sqrt{k} \)는 닫힌 꼴이 없습니다. 그러나 \( f(x) = \sqrt{x} \)가 단조증가이므로 \[ \int_{0}^{n} \sqrt{x}\,dx \;\le\; S \;\le\; \int_{1}^{n+1} \sqrt{x}\,dx, \] 양 끝을 적분하면 \( \frac{2}{3} n^{3/2} \le S \le \frac{2}{3}\big((n+1)^{3/2} - 1\big) \). 따라서 \( S \approx \frac{2}{3} n^{3/2} \)이고, 오차는 \( O(\sqrt{n}) \) 수준이에요. 이런 식으로 합의 "주된 크기"를 적분 한 줄로 잡아낼 수 있습니다.

위/아래 경계의 차이는 보통 \( f(n+1) - f(1) \) 정도로, 합 자체에 비해 훨씬 작습니다. 그래서 적분 근사는 "가장 큰 항만큼의 오차"로 합을 잡아낼 수 있는 굉장히 효율적인 도구예요.

14.4 모서리 위로 매달기 Hanging Out Over the Edge

이제 매력적인 문제 하나로 잠깐 곁길로 빠져 봅시다. 동일한 책 여러 권을 책상 모서리에 차곡차곡 쌓아서, 가장 위 책이 책상 모서리에서 가능한 한 멀리 매달리도록 하고 싶어요. 책 한 권의 길이는 1이라고 합시다. 책이 \( n \)권 있을 때, 책상 모서리에서 가장 위 책의 끝까지 거리는 최대 얼마까지 갈 수 있을까요?

물리 직관을 짚고 가면, 어떤 책 더미든 무너지지 않으려면 위쪽 더미의 무게중심이 그 아래 받침의 가장자리(또는 그 안쪽)에 있어야 합니다. 이 조건을 단계적으로 적용하면, 위에서부터 \( k \)번째 책은 그 아래 책 끝에서 \( \frac{1}{2k} \)만큼 앞으로 내밀 수 있어요(맨 위 책은 \( 1/2 \), 두 번째는 \( 1/4 \), …).

정리 14.4.1 (책 쌓기 공식)

책 \( n \)권을 위 규칙대로 쌓으면 책상 모서리에서 가장 위 책의 끝까지의 최대 거리(돌출량, overhang)는 \[ B_n \;=\; \frac{1}{2}\sum_{k=1}^{n} \frac{1}{k} \;=\; \frac{H_n}{2}. \] 여기서 \( H_n = 1 + \frac{1}{2} + \frac{1}{3} + \cdots + \frac{1}{n} \)을 \( n \)번째 조화수(harmonic number)라 부른다.

이제 결정타. 조화수는 발산합니다.

정리 14.4.2 (조화수의 발산과 근사)

\( H_n \)은 \( n \to \infty \)에서 발산하고, 더 정확히 \[ \ln(n+1) \;\le\; H_n \;\le\; 1 + \ln n. \] 따라서 \( H_n \sim \ln n \)이다.

증명 (적분 비교)

\( f(x) = 1/x \)는 양수이고 단조감소. 14.3절의 부등식에서 단조감소 버전을 쓰면 \[ \int_{1}^{n+1} \frac{dx}{x} \;\le\; \sum_{k=1}^{n} \frac{1}{k} \;\le\; 1 + \int_{1}^{n} \frac{dx}{x}. \] 양 끝을 적분하면 \( \ln(n+1) \le H_n \le 1 + \ln n \). \( \ln(n+1) \to \infty \)이므로 \( H_n \to \infty \).

이게 무슨 뜻이냐면, 책을 충분히 많이 쌓으면 돌출량 \( H_n/2 \)을 원하는 만큼 크게 만들 수 있다는 거예요. 한 도서관쯤 있다면 (이론적으로는) 마지막 책이 책상 모서리에서 한 발자국, 두 발자국, 한 블록, 한 도시 너머에까지 매달릴 수 있다는 뜻입니다. 물리적으로는 다듬지 않은 모서리, 흔들림, 마찰 같은 게 다 무시됐지만, 이상화된 이산수학 모델의 입장에서는 정말로 끝없이 멀리 갑니다.

노트 — 얼마나 천천히 가는가

다만 \( H_n \)이 \( \ln n \) 속도로만 자라기 때문에, 책 한 권 더 내밀려고 책을 어마어마하게 더 쌓아야 합니다. 돌출량을 책 한 권 길이만큼 더 늘리려면 책 수가 대략 \( e \)배가 돼야 해요. 1m 매달려면 책이 약 \( e^2 \approx 7.4 \)배의 출발점, 2m면 \( e^4 \approx 55 \)배… "발산하지만 무지하게 천천히"의 대표 사례입니다.

14.5 Products

합을 다루는 도구를 곱으로도 옮길 수 있을까요? 답은 "로그를 씌우면" 깔끔하게 됩니다. 로그는 곱을 합으로 바꿔주는 마법이거든요.

\[ \ln \prod_{k=1}^{n} a_k \;=\; \sum_{k=1}^{n} \ln a_k. \]

그러니까 곱의 점근 행동을 알고 싶으면, 로그를 취해서 합을 분석한 뒤 다시 지수로 돌아가면 됩니다. 가장 유명한 예가 팩토리얼이에요.

정리 14.5.1 (스털링 근사, Stirling's Approximation)

\[ n! \;\sim\; \sqrt{2\pi n}\left(\frac{n}{e}\right)^{n}, \] 즉 \[ \lim_{n \to \infty} \frac{n!}{\sqrt{2\pi n}\,(n/e)^n} = 1. \] 더 강하게, 양 변의 비율은 \( 1 + \frac{1}{12n} + O(1/n^2) \) 형태로 정확하게 알려져 있다.

스털링 근사를 살짝 손으로 보고 싶으면 로그를 씌워 봅시다.

\[ \ln n! = \sum_{k=1}^{n} \ln k. \]

\( \ln \)은 단조증가이므로 적분 비교에서

\[ \int_{1}^{n} \ln x\,dx \;\le\; \sum_{k=1}^{n} \ln k \;\le\; \int_{1}^{n+1} \ln x\,dx. \]

\( \int \ln x\,dx = x \ln x - x \)이므로 양 끝은 \( n \ln n - n + O(\ln n) \). 따라서

\[ \ln n! \;=\; n \ln n - n + O(\ln n), \qquad n! \;=\; e^{\,n \ln n - n + O(\ln n)} = \left(\frac{n}{e}\right)^n \cdot e^{O(\ln n)}. \]

지수의 \( O(\ln n) \) 부분이 다항식이 되어 \( \sqrt{2\pi n} \) 정도의 보정 인자를 만들어 내는데, 그 정확한 \( \sqrt{2\pi} \)는 좀 더 정밀한 분석(왈리스 곱 같은 것)에서 떨어집니다. 핵심은 적분 근사 한 번이 이렇게 거대한 결과의 뼈대를 잡아준다는 점이에요.

노트 — 컴퓨터과학에서

스털링 근사는 \( \binom{n}{k} \) 같은 이항계수의 점근 분석, 정보이론의 엔트로피 부등식, 무작위 알고리즘의 분석 등에서 꾸준히 쓰입니다. 특히 \( n! \)이 들어간 계산 복잡도 분석에서는 거의 반사적으로 \( n^n e^{-n}\sqrt{n} \) 모양으로 갈아입혀요.

14.6 어려운 합 Double Trouble

합 두 개가 겹치면 가끔 머리가 아파집니다. 그래도 하나의 일관된 원리가 거의 모든 경우에 통하는데, 바로 합의 순서를 바꿔도 된다는 사실이에요. 모든 항이 음이 아니거나, 합이 절대 수렴하면 안전합니다.

\[ \sum_{i \in I} \sum_{j \in J} a_{ij} \;=\; \sum_{j \in J} \sum_{i \in I} a_{ij}. \]

특히 합의 영역이 삼각형 모양이면 순서를 바꿔서 훨씬 쉬워지는 경우가 많아요. 예를 들어 \( i \le j \)인 \( (i,j) \) 쌍에 대해 합한다고 합시다.

예제 14.6.1 (순서 바꾸기)

\[ T \;=\; \sum_{i=1}^{n} \sum_{j=i}^{n} \frac{1}{j}. \] 안쪽 합이 \( j \)에 의존해서 다루기 까다롭습니다. 순서를 바꿔 \( j \)를 바깥으로 빼 봅시다. \( i \le j \le n \)이라는 조건은 같은데, 이번엔 \( j \)를 먼저 잡고 \( i \)가 \( 1 \)부터 \( j \)까지 가도록 합니다. \[ T \;=\; \sum_{j=1}^{n} \sum_{i=1}^{j} \frac{1}{j} \;=\; \sum_{j=1}^{n} \frac{j}{j} \;=\; \sum_{j=1}^{n} 1 \;=\; n. \] 안쪽 합이 \( i \)에 무관해서 깔끔히 떨어집니다. \( T = n \). 처음 식을 보고 이 답을 짐작하긴 쉽지 않죠.

예제 14.6.2 (조화수의 합)

\( \sum_{k=1}^{n} H_k \)를 구해 봅시다. 정의를 펼쳐 쓰면 \[ \sum_{k=1}^{n} H_k \;=\; \sum_{k=1}^{n} \sum_{j=1}^{k} \frac{1}{j}. \] \( j \)를 바깥으로 빼면 \( j \le k \le n \)이므로 \( k \)는 \( j \)부터 \( n \)까지. \[ = \sum_{j=1}^{n} \sum_{k=j}^{n} \frac{1}{j} \;=\; \sum_{j=1}^{n} \frac{n - j + 1}{j} \;=\; (n+1)H_n - n. \]

이중 합 다루는 마음가짐은 단순합니다 — "지수와 그 범위를 그림으로 그려 보고, 지금 안쪽이 어려우면 바깥으로 보낼 수 있는지 보자". 그게 잘 통하면 무지막지해 보이던 합이 갑자기 정리됩니다.

노트 — 조심해야 할 때

합의 순서 교환은 모든 항이 양수이거나 합이 절대 수렴할 때만 안전합니다. 양수와 음수가 섞이고 조건부 수렴만 하는 경우(예: 교대 조화급수의 재배열)는 답이 바뀌기까지 해요. 다행히 알고리즘 분석에서 만나는 합은 대부분 음이 아닌 항들의 유한합이라 이 위험을 신경 쓸 일이 거의 없습니다.

14.7 점근 표기법 Asymptotic Notation

드디어 알고리즘 수업의 단골손님, 빅 오 표기법(Big-O notation)입니다. 컴퓨터과학 학생이 평생 가장 자주 쓰는 수학 표기 중 하나이고, 그래서 정의가 흐릿하면 평생 헷갈립니다. 한 번 깔끔하게 정리하고 갑시다.

다섯 가지 기호 — \( O, \Omega, \Theta, o, \omega \) — 가 있고, 이들은 모두 두 함수 \( f, g : \mathbb{N} \to \mathbb{R}_{>0} \)의 큰 \( n \)에서의 상대적 크기를 표현합니다.

정의 14.7.1 (다섯 가지 점근 표기)

\( f, g \)가 양의 함수일 때:

빅 오: \( f(n) = O(g(n)) \) \( \iff \) 어떤 상수 \( c > 0 \)과 \( n_0 \)가 있어서 모든 \( n \ge n_0 \)에 대해 \( f(n) \le c\, g(n) \).

빅 오메가: \( f(n) = \Omega(g(n)) \) \( \iff \) 어떤 \( c > 0,\, n_0 \)가 있어서 \( n \ge n_0 \)면 \( f(n) \ge c\, g(n) \).

빅 세타: \( f(n) = \Theta(g(n)) \) \( \iff \) \( f = O(g) \)이고 \( f = \Omega(g) \).

리틀 오: \( f(n) = o(g(n)) \) \( \iff \) \( \lim_{n\to\infty} f(n)/g(n) = 0 \).

리틀 오메가: \( f(n) = \omega(g(n)) \) \( \iff \) \( \lim_{n\to\infty} f(n)/g(n) = \infty \).

직관은 이렇습니다. \( O \)는 "위로 \( g \)에 의해 (상수배까지) 눌린다", \( \Omega \)는 "아래로 \( g \)만큼은 자란다", \( \Theta \)는 "위아래로 똑같이 자란다 = 같은 차수". 소문자 \( o \)와 \( \omega \)는 부등호가 엄격한 버전이에요. \( o(g) \)는 "정말 \( g \)보다 무시할 만큼 작다", \( \omega(g) \)는 "정말 \( g \)보다 압도적으로 크다".

흔히 헷갈리는 포인트 몇 개를 정리해 둡시다.

노트 — 등호 \( = \)는 등호가 아니다

\( f(n) = O(g(n)) \)에서 \( = \)는 일반적인 등호가 아니라 "어떤 집합에 속한다"의 약식 표기입니다. 즉 \( f \in O(g) \)의 의미예요. 그래서 \( O(n) = O(n^2) \)이라고는 써도 \( O(n^2) = O(n) \)이라곤 못 씁니다 — 한 방향만 성립하니까요. 처음엔 어색하지만 관습으로 굳어진 표기이니 익숙해져야 해요.

예제 14.7.2 (계산 한 줌)

(a) \( 5n^2 + 3n + 7 = O(n^2) \). 이유: \( n \ge 1 \)이면 \( 5n^2 + 3n + 7 \le 5n^2 + 3n^2 + 7n^2 = 15n^2 \), 즉 \( c = 15, n_0 = 1 \)로 OK.

(b) \( 5n^2 + 3n + 7 = \Theta(n^2) \). 위에서 \( O(n^2) \) 보였고, 아래로는 \( 5n^2 + 3n + 7 \ge 5n^2 \)이므로 \( \Omega(n^2) \)도 됨.

(c) \( n \log n = o(n^2) \). 왜냐하면 \( (n\log n)/n^2 = (\log n)/n \to 0 \).

(d) \( 2^n = \omega(n^k) \) (모든 고정 상수 \( k \)에 대해). 지수는 다항식보다 압도적으로 빠르게 자란다.

이 표기법이 알고리즘 분석에서 왜 그렇게 사랑받느냐 하면, 우리가 보통 신경 쓰는 게 "코드 한 줄당 정확한 상수"가 아니라 "입력이 두 배가 되면 시간이 어떻게 변하느냐"이기 때문입니다. 상수 계수와 낮은 차수 항을 다 무시해도 그 본질은 변하지 않아요. 그래서:

  • 이진 탐색: \( \Theta(\log n) \)
  • 선형 탐색: \( \Theta(n) \)
  • 병합 정렬: \( \Theta(n \log n) \)
  • 버블 정렬: \( \Theta(n^2) \) 최악
  • 외판원의 brute force: \( \Theta(n!) \) — 사실상 손도 못 댐

노트 — 흔한 함정 두 가지

(1) "최악의 경우(worst-case) 시간은 \( O(g) \)"와 "모든 입력에서 시간은 \( O(g) \)"는 같은 말입니다. 반대로 "최악의 경우 시간이 \( \Omega(g) \)"는 "어떤 입력에서는 시간이 \( g \) 이상"이라는 뜻이에요. 양적 의미를 헷갈리지 말 것.

(2) \( O \)는 상한, \( \Omega \)는 하한, \( \Theta \)는 둘 다. 학생들이 종종 "이 알고리즘은 \( O(n^2) \)이다"라는 표현을 보고 "정확히 \( n^2 \)에 비례한다"로 읽는데, \( O(n^2) \)는 그저 위로 \( n^2 \)에 의해 막힌다는 약한 진술입니다. \( \Theta \)를 써야 정확한 차수가 됩니다.

정리 14.7.3 (점근의 산술)

\( f_1 = O(g_1) \)이고 \( f_2 = O(g_2) \)이면: \[ f_1 + f_2 = O(\max(g_1, g_2)), \qquad f_1 \cdot f_2 = O(g_1 \cdot g_2). \] 특히 다항식 \( a_d n^d + a_{d-1} n^{d-1} + \cdots + a_0 \)는 \( \Theta(n^d) \)이다 (\( a_d > 0 \)인 경우).

마지막으로 한 가지 비교를 강조해 둡시다. 큰 \( n \)에서 자주 등장하는 함수들의 성장 속도 순서는 다음과 같습니다 (왼쪽이 더 느리게 자람).

\[ 1 \;\prec\; \log\log n \;\prec\; \log n \;\prec\; \sqrt{n} \;\prec\; n \;\prec\; n \log n \;\prec\; n^2 \;\prec\; n^c \;(c>2) \;\prec\; 2^n \;\prec\; n! \;\prec\; n^n. \]

여기서 \( \prec \)는 "리틀 오"를 뜻해요 — 좌변이 우변에 비해 압도적으로 작다는 뜻입니다. 알고리즘을 설계하다 어떤 단계가 \( O(n^3) \)이고 다른 단계가 \( O(n \log n) \)이면, 큰 \( n \)에서 후자는 사실상 무시된다는 식의 직관을 위 사슬이 깔끔하게 정리해 줍니다.

노트 — 이번 장을 마치며

이번 장에서 배운 것들은 한 가지 큰 흐름으로 묶입니다 — "정확히 못 풀 땐 근사한다". 등비급수 같은 깔끔한 공식이 안 통할 때 적분으로 갈아타고, 거기서 나온 점근 결과를 \( O, \Theta \) 같은 언어로 정리한다. 다음 장(15장)의 점화식과 함께 이 도구들은 알고리즘 분석 수업의 척추 역할을 하게 됩니다. \( T(n) = 2T(n/2) + O(n) \) 같은 점화식이 결국 \( \Theta(n \log n) \)이 된다는 식의 결론으로 가는 길에서, 이번 장의 합과 적분 비교 기술이 거의 매번 등장할 거예요.

PART III — 세기

15 기수 규칙 Cardinality Rules

이산수학에서 세기는 더하기보다 강력합니다. 비밀번호 공간의 크기, 알고리즘의 가능한 상태 수, 확률 문제의 표본공간 — 이런 것들은 모두 "몇 개냐?"라는 단 하나의 질문으로 환원됩니다. 이 챕터에서는 그 질문에 답하는 핵심 도구들을 모아둡니다. 전단사를 이용한 카운팅, 곱 규칙, 나누기 규칙, 이항계수, 비둘기집, 포함-배제, 그리고 같은 양을 두 가지 방식으로 세서 항등식을 증명하는 조합적 증명까지. 손에 익히면 평생 써먹는 무기입니다.

15.1 다른 것을 세어 무언가 세기 Counting One Thing by Counting Another

어떤 집합의 원소를 직접 세기 어려울 때, 우리는 자주 "세기 쉬운 다른 집합과 짝을 지어준다"는 전략을 씁니다. 두 집합 사이에 일대일 대응(전단사)을 만들면, 한쪽의 크기를 알자마자 다른 쪽의 크기가 따라옵니다. 이게 카운팅의 가장 근본적인 원리예요.

정의 15.1.1 (전단사 카운팅 원리)

유한집합 \(A, B\)에 대해 전단사 \(f: A \to B\)가 존재하면 \(|A| = |B|\)이다.

말로 하면 당연해 보이지만, 이 단순한 사실이 카운팅의 거의 모든 트릭을 떠받칩니다. 직접 세기 곤란한 \(A\)를 들고 있으면, 더 친숙한 \(B\)와 짝지어 \(|A|\)를 \(|B|\)로 갈아끼웁니다.

예제 15.1.2 (3원소 부분집합 vs. 0/1 길이 \(n\) 수열)

\(\{1, 2, \dots, n\}\)의 부분집합의 개수를 셉니다. 부분집합 \(S\)마다 길이 \(n\)의 비트열 \(b_1 b_2 \cdots b_n\)을 대응시킵니다. \(b_i = 1\)이면 \(i \in S\), 아니면 \(i \notin S\). 이 대응은 명백히 전단사이고, 비트열은 자리마다 두 가지이므로 \(2^n\)개입니다. 따라서 \(\{1, \dots, n\}\)의 부분집합도 \(2^n\)개.

"직접 세지 마라, 짝지어라" — 이 챕터의 보이지 않는 슬로건입니다. 다음 절부터 짝지을 만한 표준 집합들 (수열, 순열, 조합 등)을 차례로 만들어둡니다.

15.2 수열 세기 Counting Sequences

카운팅의 첫 번째 도구상자는 수열입니다. 자리마다 어떤 집합에서 원소를 하나씩 골라 늘어놓는 것이죠. 자리들이 서로 독립이라면 단순한 곱셈이 답을 줍니다.

정리 15.2.1 (곱 규칙, Product Rule)

유한집합 \(P_1, P_2, \dots, P_k\)에 대해, 카르테시안 곱의 크기는 \(|P_1 \times P_2 \times \cdots \times P_k| = |P_1| \cdot |P_2| \cdots |P_k|.\)

특히 모든 자리가 같은 집합 \(P\)(\(|P| = n\))에서 골라지고 자리 수가 \(k\)이면 수열의 개수는 \(n^k\)입니다.

예제 15.2.2 (비밀번호의 무서움)

영문 소문자만 쓰는 8자리 비밀번호의 개수는 \(26^8 \approx 2.09 \times 10^{11}\). 이걸 영문 대소문자 + 숫자(62종)로 늘리면 \(62^8 \approx 2.18 \times 10^{14}\)로 1000배 커집니다. "한 자리만 더, 한 종류만 더" 같은 작은 변화가 거대한 차이를 만든다는 게 곱 규칙의 위력이에요.

예제 15.2.3 (DNA 가닥)

길이 \(n\)의 DNA 서열 — 각 자리에 A, C, G, T 중 하나 — 은 \(4^n\)개. \(n=20\)만 되어도 \(4^{20} = 2^{40} \approx 1.1 \times 10^{12}\)로 인간 게놈 한 곳을 검색하기에 충분히 많습니다.

이 단순한 \(n^k\) 수식 하나로 자료구조의 상태 공간, 해시 함수의 출력 공간, 트리의 노드 수 같은 것들이 한꺼번에 다뤄집니다. 곱 규칙이 카운팅의 \(+\)이라면, 다음 절의 일반화된 곱 규칙은 \(\times\)입니다.

15.3 일반화된 곱 규칙 The Generalized Product Rule

현실의 선택은 종종 "앞에서 무엇을 골랐느냐"에 따라 다음에 가능한 선택지가 달라집니다. 이때도 곱 규칙은 유효한데, 다만 각 자리의 경우의 수가 일정하기만 하면 됩니다.

정리 15.3.1 (일반화된 곱 규칙)

길이 \(k\)의 수열 \( (s_1, s_2, \dots, s_k) \)를 만들 때, \(s_1\)을 \(n_1\)가지로 고를 수 있고, \(s_1\)이 어떻게 정해졌든 \(s_2\)를 \(n_2\)가지로, …, \(s_{i-1}\)까지가 어떻게 정해졌든 \(s_i\)를 \(n_i\)가지로 고를 수 있다면, 가능한 수열의 총 개수는 \(n_1 \cdot n_2 \cdots n_k\)이다.

각 단계의 가짓수가 이전 선택에 의존하더라도, 의존 결과의 크기가 일정하기만 하면 곱셈이 통한다 — 이게 핵심입니다.

예제 15.3.2 (\(n!\)의 등장)

\(\{1, 2, \dots, n\}\)의 모든 원소를 한 번씩 늘어놓는 방법(순열)의 수를 셉니다. 첫 자리는 \(n\)가지, 그 다음 자리는 무엇을 골랐든 남은 \(n-1\)가지, …, 마지막 자리는 \(1\)가지. 따라서 순열의 수는 \(n \cdot (n-1) \cdots 2 \cdot 1 = n!\). 이게 그 유명한 팩토리얼입니다.

예제 15.3.3 (서로 다른 카드 순서)

52장 카드를 한 줄로 늘어놓는 방법은 \(52! \approx 8.06 \times 10^{67}\). 이 수는 우주의 별 개수보다 훨씬 큽니다. 카드를 잘 섞었을 때 같은 순서가 우연히 두 번 나올 확률이 사실상 0인 이유가 여기에 있어요.

\(k\)개를 뽑아 늘어놓는 \(k\)-순열의 수는 \(n(n-1)\cdots(n-k+1) = \dfrac{n!}{(n-k)!}\)이고, 자주 \(P(n,k)\)로 씁니다. 곧 보겠지만 이 식은 다음 절들과 빠르게 얽혀 들어갑니다.

15.4 나누기 규칙 The Division Rule

때로는 "필요 이상으로 많이 센 다음" 중복분으로 나누는 게 가장 빠른 길입니다. 모든 원소가 똑같이 \(k\)번씩 세어졌다는 사실만 잡으면, 답은 전체 / \(k\)예요.

정리 15.4.1 (나누기 규칙)

함수 \(f: A \to B\)가 \(k\)-대-\(1\) 매핑이면, 즉 모든 \(b \in B\)에 대해 \(|f^{-1}(b)| = k\)이면, \(|A| = k \cdot |B|\), 따라서 \(|B| = |A|/k\).

예제 15.4.2 (원탁에 둘러앉기)

\(n\)명을 원탁에 앉히는 자리 배치 수를 셉니다. 자리에 번호를 매겨 일렬 순열로 보면 \(n!\)가지인데, 원탁에서는 회전해서 같은 배치는 한 가지로 봅니다. 회전은 \(n\)가지이므로 \(n\)-대-\(1\) 매핑이 생기고, 답은 \(n!/n = (n-1)!\). 거울 대칭까지 같다고 보면 다시 \(2\)로 더 나누어 \((n-1)!/2\).

예제 15.4.3 (\(k\)-순열에서 \(k\)-조합으로)

\(\{1, \dots, n\}\)에서 \(k\)개를 뽑아 늘어놓는 방법은 \(P(n,k) = n!/(n-k)!\). 그런데 같은 \(k\)개의 원소들은 \(k!\)가지로 늘어놓을 수 있으니, "순서 무시"로 보면 \(k!\)-대-\(1\) 매핑입니다. 따라서 \(k\)개를 순서 무시하고 뽑는 방법, 즉 \(k\)-부분집합의 수는 \[ \binom{n}{k} = \frac{n!}{k!\,(n-k)!}. \]

나누기 규칙은 본질적으로 "대칭이 있는 곳에서는 너무 많이 세어졌으니 대칭 횟수로 나눠라"라는 직관입니다. 알고리즘 분석에서 등가 클래스를 셀 때, 그래프의 라벨 없는 형태를 셀 때 끊임없이 재등장합니다.

15.5 부분집합 세기 Counting Subsets

앞에서 자연스럽게 등장한 \(\binom{n}{k}\)는 이산수학 전체에서 가장 자주 등장하는 수일지도 모릅니다. \(n\)개에서 \(k\)개를 순서 없이 고르는 방법의 수, 일명 이항계수예요.

정의 15.5.1 (이항계수)

음이 아닌 정수 \(n, k\)에 대해 \[ \binom{n}{k} = \frac{n!}{k!\,(n-k)!} \quad (0 \le k \le n), \] 그 밖에는 \(0\). 읽기는 "n choose k".

예제 15.5.2 (작은 값들)

\(\binom{5}{2} = 10\) (5명에서 2명 뽑기), \(\binom{10}{3} = 120\) (10개 토픽에서 3개 고르기), \(\binom{n}{0} = \binom{n}{n} = 1\). 또한 대칭성 \(\binom{n}{k} = \binom{n}{n-k}\) — \(k\)개를 고르는 것과 \(n-k\)개를 "남기는 것"이 같은 일이라는 직관에서 바로 나옵니다.

정리 15.5.3 (파스칼 항등식)

\(1 \le k \le n\)에 대해 \[ \binom{n}{k} = \binom{n-1}{k-1} + \binom{n-1}{k}. \]

증명 (조합적 논증)

\(\{1, 2, \dots, n\}\)의 \(k\)-부분집합을 셉니다. 원소 \(n\)을 포함하느냐로 두 경우로 가릅니다. 포함하면 나머지 \(k-1\)개를 \(\{1, \dots, n-1\}\)에서 골라야 하므로 \(\binom{n-1}{k-1}\)가지. 포함하지 않으면 \(k\)개 모두를 \(\{1, \dots, n-1\}\)에서 골라야 하므로 \(\binom{n-1}{k}\)가지. 두 경우는 서로소이고 모든 \(k\)-부분집합을 빠짐없이 덮으므로 합이 \(\binom{n}{k}\).

파스칼 항등식은 파스칼 삼각형을 한 줄씩 채우는 점화식이고, 동적계획법으로 \(\binom{n}{k}\)를 \(O(nk)\)에 정수 산술로 계산하는 알고리즘의 뿌리이기도 합니다.

15.6 반복 있는 수열 Sequences with Repetitions

이번에는 같은 글자가 여러 번 나오는 단어를 늘어놓는 문제입니다. 예를 들어 "MISSISSIPPI"의 글자들을 모두 한 번씩 사용해 만들 수 있는 서로 다른 단어는 몇 개일까요?

정리 15.6.1 (다중집합 순열)

\(n\)개의 자리 중 \(k_1\)자리에 1번 글자, \(k_2\)자리에 2번 글자, …, \(k_m\)자리에 \(m\)번 글자가 들어가는 (단, \(k_1 + \cdots + k_m = n\)) 단어의 수는 \[ \binom{n}{k_1, k_2, \dots, k_m} = \frac{n!}{k_1!\,k_2!\,\cdots k_m!}. \] 이를 다항계수(multinomial coefficient)라고 부릅니다.

예제 15.6.2 (MISSISSIPPI)

총 11글자, M 1개, I 4개, S 4개, P 2개. 따라서 \[ \frac{11!}{1!\,4!\,4!\,2!} = 34650. \]

또 하나 자주 나오는 문제는 구분되지 않는 \(n\)개의 공을 구분되는 \(k\)개의 상자에 나누어 담는 방법의 수입니다. 이건 그 유명한 "별과 막대"로 셉니다.

정리 15.6.3 (별과 막대)

\(x_1 + x_2 + \cdots + x_k = n\)을 만족하는 음이 아닌 정수 해 \( (x_1, \dots, x_k)\)의 개수는 \(\binom{n+k-1}{k-1}\).

증명 스케치

\(n\)개의 별 \(\star\)을 늘어놓고 사이에 \(k-1\)개의 막대 \(|\)를 끼워 넣습니다. 막대 사이의 별 개수가 각 \(x_i\)가 되죠. 별 \(n\)개와 막대 \(k-1\)개로 이뤄진 길이 \(n+k-1\) 수열 중 막대의 위치를 고르는 것이므로 \(\binom{n+k-1}{k-1}\).

예제 15.6.4 (도넛 6개를 4종류 중에서 고르기)

같은 종류의 도넛은 구별하지 않고 6개를 4종류에서 고른다면 \(\binom{6+4-1}{4-1} = \binom{9}{3} = 84\)가지.

15.7 카운팅 연습: 포커 핸드 Counting Practice: Poker Hands

카운팅 도구가 정말로 익었는지 확인하는 가장 즐거운 방법은 포커입니다. 표준 52장 덱(13개 랭크 × 4개 슈트)에서 5장의 손패를 받습니다. 가능한 손패의 총 수는 \(\binom{52}{5} = 2{,}598{,}960\). 이걸 분모 삼아 각 족보의 확률을 계산해봅니다.

예제 15.7.1 (풀하우스)

쓰리카드 + 페어. 쓰리카드의 랭크를 고르고 (13가지), 그 랭크에서 4장 중 3장을 고르고 (\(\binom{4}{3} = 4\)), 페어의 랭크를 남은 12개에서 고르고 (12가지), 그 랭크에서 4장 중 2장을 고른다 (\(\binom{4}{2} = 6\)). \[ 13 \cdot 4 \cdot 12 \cdot 6 = 3744. \] 확률은 \(3744 / 2598960 \approx 0.00144\), 약 \(1/694\).

예제 15.7.2 (플러시, 스트레이트 플러시 제외 안 함)

같은 슈트 5장. 슈트 4가지 중 하나를 고르고, 그 슈트 13장에서 5장을 고른다. \[ 4 \cdot \binom{13}{5} = 4 \cdot 1287 = 5148. \] 그 중 스트레이트 플러시(연속 랭크)가 \(4 \cdot 10 = 40\)개. 따라서 "그냥 플러시"는 \(5148 - 40 = 5108\)이고 확률은 약 \(0.00197\).

예제 15.7.3 (투페어)

서로 다른 두 랭크의 페어 + 또 다른 한 랭크의 한 장. 페어 두 랭크 고르기 \(\binom{13}{2} = 78\), 각 랭크에서 페어 만들기 \(\binom{4}{2}^2 = 36\), 마지막 한 장의 랭크는 남은 11개에서 (11), 그 랭크에서 한 장 고르기 (4). \[ 78 \cdot 36 \cdot 11 \cdot 4 = 123552. \] 확률 약 \(0.0475\), 즉 \(1/21\) 정도. 생각보다 자주 나옵니다.

포커가 좋은 이유는 같은 손패를 두 번 세는 함정이 곳곳에 숨어 있기 때문입니다. 예를 들어 "쓰리카드 랭크는 13가지, 페어 랭크는 13가지"로 잡으면 같은 랭크를 동시에 골라버리는 모순이 생기죠. 의존적인 선택은 일반화된 곱 규칙에 충실해야 한다는 좋은 교훈입니다.

15.8 비둘기집 원리 The Pigeonhole Principle

가장 단순해 보이지만 가장 자주 쓰는 카운팅 무기 — 비둘기집. 비둘기 \(n+1\)마리를 비둘기집 \(n\)개에 넣으면, 어떤 비둘기집에는 둘 이상이 들어 있다. 너무 당연하지 않나요? 그런데 이 한 줄이 종종 마법을 부립니다.

정리 15.8.1 (비둘기집 원리)

유한집합 \(A, B\)가 \(|A| > |B|\)일 때, 어떤 함수 \(f: A \to B\)도 단사일 수 없다. 즉 \(f(a_1) = f(a_2)\)인 서로 다른 \(a_1, a_2 \in A\)가 존재한다.

정리 15.8.2 (일반화된 비둘기집)

\(|A| > k \cdot |B|\)이면 어떤 \(b \in B\)에 대해 \(|f^{-1}(b)| \ge k+1\), 즉 같은 값으로 보내지는 \(A\)의 원소가 \(k+1\)개 이상 있다.

예제 15.8.3 (서울에 같은 머리카락 수)

사람의 머리카락 수는 많아야 100만 개 정도. 서울 인구는 900만이 넘습니다. 비둘기집 원리에 따라 머리카락 수가 정확히 같은 사람이 적어도 두 명 — 사실은 일반화 비둘기집으로 적어도 9명 — 존재합니다. 직접 한 명도 본 적 없지만 분명히 있어요.

예제 15.8.4 (악수와 친구)

파티에 \(n \ge 2\)명이 있을 때, 같은 사람 수와 악수한 두 사람이 반드시 있습니다. 한 사람의 악수 가능 횟수는 \(0, 1, \dots, n-1\)의 \(n\)가지인데, 0과 \(n-1\)은 동시에 나올 수 없으니 (모두와 악수한 사람이 있으면 아무와도 악수 안 한 사람은 없으므로) 실제 가능 값은 \(n-1\)가지뿐. \(n\)명을 \(n-1\)개 비둘기집에 넣은 격이라 충돌 발생.

예제 15.8.5 (중복된 부분합)

임의의 정수 \(a_1, a_2, \dots, a_n\)이 주어지면, 그 중 연속 부분의 합이 \(n\)으로 나누어떨어지는 것이 항상 존재합니다. 부분합 \(S_i = a_1 + \cdots + a_i\) (\(i = 1, \dots, n\))의 \(n\)으로 나눈 나머지를 봅니다. 나머지 후보는 \(0, 1, \dots, n-1\)의 \(n\)가지. 만약 어느 \(S_i\)가 0이면 끝. 아니면 \(n-1\)가지 비제로 나머지에 \(n\)개의 \(S_i\)가 들어가니, 같은 나머지를 갖는 \(S_i, S_j\) (\(i < j\))가 존재하고 \(S_j - S_i = a_{i+1} + \cdots + a_j\)가 \(n\)의 배수.

비둘기집은 카운팅 정리라기보다 존재 증명의 도구입니다. "있다"고 주장만 하고 누군지는 모르는 비구성적 증명의 전형이에요.

15.9 포함-배제 Inclusion-Exclusion

합집합의 크기를 셀 때 단순히 더하면 겹치는 부분이 두 번 세어집니다. 이걸 정확히 보정해주는 공식이 포함-배제예요. 두 집합이면 모두 알고 있는 \(|A \cup B| = |A| + |B| - |A \cap B|\)인데, 이걸 일반화한 모습이 이렇습니다.

정리 15.9.1 (포함-배제 원리)

유한집합 \(A_1, A_2, \dots, A_n\)에 대해 \[ \left| \bigcup_{i=1}^{n} A_i \right| = \sum_{i} |A_i| - \sum_{i

증명의 직관: 합집합의 한 원소가 정확히 \(m\)개의 \(A_i\)에 속한다면, 우변에서 그 원소는 \(\binom{m}{1} - \binom{m}{2} + \cdots + (-1)^{m+1} \binom{m}{m}\)번 세어지고, 이 합은 \(1 - (1-1)^m = 1\). 따라서 정확히 한 번 세어집니다.

예제 15.9.2 (서로소 순열, derangement)

\(\{1, 2, \dots, n\}\)의 순열 중 \(\pi(i) \ne i\)인, 즉 어떤 원소도 자기 자리에 머물지 않는 순열의 수 \(D_n\)을 셉니다. \(A_i\)를 "\(\pi(i) = i\)인 순열의 집합"이라 두면, 우리가 원하는 것은 \(n! - |A_1 \cup \cdots \cup A_n|\). \(k\)개의 인덱스를 고정하면 나머지는 자유로우니 \( |A_{i_1} \cap \cdots \cap A_{i_k}| = (n-k)!\)이고, 그런 인덱스 조합은 \(\binom{n}{k}\)개. \[ |A_1 \cup \cdots \cup A_n| = \sum_{k=1}^{n} (-1)^{k+1} \binom{n}{k}(n-k)!. \] 따라서 \[ D_n = \sum_{k=0}^{n} (-1)^{k} \binom{n}{k}(n-k)! = n! \sum_{k=0}^{n} \frac{(-1)^k}{k!}. \] 흥미롭게도 \(D_n / n! \to 1/e\)이므로, \(n\)이 커지면 무작위 순열이 서로소 순열일 확률은 약 \(36.8\%\)에 수렴합니다.

예제 15.9.3 (전사 함수의 수)

\(f: \{1, \dots, n\} \to \{1, \dots, k\}\) 중 전사인 함수의 수는 포함-배제로 \[ \sum_{i=0}^{k} (-1)^i \binom{k}{i} (k-i)^n. \] "값으로 빠뜨려진 원소"가 있는 함수를 빼나가는 식입니다.

포함-배제는 식 자체는 무서워 보이지만 적용 과정은 거의 기계적입니다. 어떤 "나쁜 조건들"이 합집합으로 묶이는 문제를 만나면 거의 자동으로 떠올리세요.

15.10 조합적 증명 Combinatorial Proofs

이항계수 항등식 같은 식을 보면 보통 양변을 식으로 펼쳐 같은 다항식임을 보이려고 하죠. 그런데 더 우아한 길이 있습니다 — 같은 집합을 두 가지 방법으로 세서 양변이 같음을 보이는 것입니다. 이걸 조합적 증명이라고 합니다.

정리 15.10.1 (이항정리, 조합적 형태)

\[ \sum_{k=0}^{n} \binom{n}{k} = 2^n. \]

증명 (양쪽으로 세기)

\(\{1, \dots, n\}\)의 부분집합의 총 수를 두 방법으로 셉니다. 첫째: 각 원소가 들어가느냐 마느냐를 독립적으로 정하므로 \(2^n\). 둘째: 부분집합을 크기로 분류해 더하면 \(\sum_{k=0}^{n} \binom{n}{k}\). 두 방법 모두 같은 집합을 셌으니 \(\sum \binom{n}{k} = 2^n\).

정리 15.10.2 (방데르몽드 항등식)

\[ \binom{m+n}{r} = \sum_{k=0}^{r} \binom{m}{k}\binom{n}{r-k}. \]

증명 (조합적)

\(m\)명의 남자와 \(n\)명의 여자가 있는 그룹에서 \(r\)명의 위원회를 뽑는 방법을 세어봅니다. 좌변: 그냥 \(m+n\)명에서 \(r\)명 고르면 \(\binom{m+n}{r}\). 우변: 위원회 안의 남자 수 \(k\)로 분류 — 남자 \(k\)명을 고르고 (\(\binom{m}{k}\)) 여자 \(r-k\)명을 고른다 (\(\binom{n}{r-k}\)) — 모두 더하면 \(\sum_k \binom{m}{k}\binom{n}{r-k}\). 같은 일을 두 가지로 셌으니 등식.

예제 15.10.3 (\(k \binom{n}{k} = n \binom{n-1}{k-1}\))

\(\{1, \dots, n\}\)에서 \(k\)명짜리 위원회를 만들고 그 중 한 명을 위원장으로 뽑는 방법을 셉니다. 좌변: 위원회를 먼저 (\(\binom{n}{k}\)), 그 안에서 위원장 한 명 (\(k\)). 우변: 위원장을 먼저 \(n\)명 중 한 명, 나머지 \(n-1\)명 중 \(k-1\)명을 추가 위원으로 (\(\binom{n-1}{k-1}\)). 두 방법이 같으므로 \(k \binom{n}{k} = n \binom{n-1}{k-1}\).

식 변형으로 푸는 증명이 "그렇다"라는 사실만 알려준다면, 조합적 증명은 "왜 그런지"를 보여줍니다. 같은 객체를 두 방법으로 세는 습관이 들면 이항계수에 관한 거의 모든 항등식이 자명해 보이기 시작해요. 카운팅이 단순한 수 세기 기법을 넘어 증명 기술이 되는 순간입니다.

노트 (이 챕터의 한 줄 정리)

직접 세지 말고 짝지어라. 자리들이 독립이면 곱하라. 의존적이면 일반화된 곱. 너무 많이 세었으면 나누어라. 합집합엔 포함-배제. 비둘기 \(n+1\)마리 \(n\)개 집엔 충돌이 있다. 그리고 같은 것을 두 방법으로 세면 항등식이 떨어진다 — 이게 카운팅 챕터의 모든 것입니다.

PART III — 세기

16 생성함수 Generating Functions

수열을 손에 들고 있기 어려우면, 한 함수로 묶어서 들고 다닌다 — 그게 생성함수입니다. 이 챕터에서는 수열 \( a_0, a_1, a_2, \dots \)를 형식 멱급수 \( A(x) = \sum a_n x^n \)으로 인코딩한 다음, 함수에 대한 대수적 조작이 곧 수열에 대한 카운팅 조작이 되는 마법을 살펴봅니다. 동전 거스름돈을 세고, 부분분수로 계수를 끄집어내고, 점화식을 폐형(closed form)으로 풀어보면서 이 도구가 왜 조합론의 스위스 군용 칼이라 불리는지 체감하게 됩니다.

16.1 무한급수 Infinite Series

수학자가 수열을 다루는 방법은 여러 가지가 있지만, 그중에서도 가장 강력한 트릭 하나는 “수열을 함수로 변환하기”입니다. 수열 \( (a_0, a_1, a_2, \dots) \)가 있으면, 우리는 다음과 같이 멱급수 한 줄로 묶어버립니다.

정의 16.1.1 (생성함수)

수열 \( (a_n)_{n \ge 0} \)의 (보통) 생성함수란 형식 멱급수 \[ A(x) = \sum_{n=0}^{\infty} a_n x^n = a_0 + a_1 x + a_2 x^2 + a_3 x^3 + \cdots \] 를 말합니다. 즉, 수열을 \( x^n \)의 계수에 “끼워 넣은” 다항식 비슷한 무한합이에요.

여기서 \( x \)는 어떤 구체적인 숫자가 아니라 그냥 자리표시자(placeholder)입니다. 수열의 정보를 잃지 않고 보관하기 위한 옷걸이라고 생각하면 좋아요. \( x = 0.3 \) 같은 걸 대입할 일은 일단 없습니다. 그래서 “수렴 반경이 어떻게 되나” 같은 해석학적 걱정은 16.5에서 따로 정리할 거예요.

가장 처음 만나야 할 항등식 한 줄이 있습니다. 모든 항이 1인 수열 \( (1, 1, 1, 1, \dots) \)의 생성함수는 무엇일까요?

\[ 1 + x + x^2 + x^3 + \cdots = \frac{1}{1 - x}. \]

이 식은 고등학교 등비급수 공식에서 \( |x| < 1 \) 조건으로 외우던 그 식이지만, 형식 멱급수 세계에서는 양변이 “같은 수열을 인코딩한다”는 뜻으로 그대로 받아들이면 됩니다. 곱해서 확인해 볼까요. \( (1-x)(1 + x + x^2 + \cdots) \)를 분배법칙으로 풀면 \( 1 + x + x^2 + \cdots - x - x^2 - x^3 - \cdots \)가 되어 가운데 항들이 깔끔히 상쇄되고 1만 남습니다.

예제 16.1.2 (자주 쓰이는 생성함수 모음)

아래 항등식들은 “주머니에 넣고 다니는” 기본 도구입니다.

\[ \frac{1}{1-x} = \sum_{n \ge 0} x^n, \qquad \frac{1}{1-cx} = \sum_{n \ge 0} c^n x^n, \] \[ \frac{1}{(1-x)^2} = \sum_{n \ge 0} (n+1) x^n, \qquad \frac{x}{(1-x)^2} = \sum_{n \ge 0} n\, x^n. \]

마지막 식은 “\( a_n = n \)”인 수열의 생성함수예요. 첫 번째 식의 양변을 \( x \)에 대해 미분해서 얻을 수도 있습니다 (형식적으로요).

노트 — 수열과 함수, 어느 쪽이 본체?

처음에는 “식이 본체”라고 생각하기 쉽지만, 생성함수의 세계에서는 수열이 본체이고 함수는 그 수열을 보관하는 가방입니다. \( \frac{1}{1-x} \)라고 쓰면 사실은 “모든 항이 1인 수열”을 부르는 별명을 부른 셈이에요. 별명을 익히면 수열을 다루기 훨씬 가벼워집니다.

16.2 생성함수로 세기 Counting with Generating Functions

생성함수가 단순히 “수열을 식으로 바꾸기” 놀이에서 그쳤다면 이렇게 큰 단원을 차지할 이유가 없죠. 진짜 마법은 두 수열의 생성함수를 곱하면, 그 곱이 어떤 카운팅을 자동으로 수행해 준다는 데 있습니다.

정리 16.2.1 (수열 곱 = 컨벌루션)

두 생성함수 \( A(x) = \sum a_n x^n \)과 \( B(x) = \sum b_n x^n \)을 곱하면 \[ A(x) B(x) = \sum_{n=0}^{\infty} c_n x^n, \quad \text{단, } c_n = \sum_{k=0}^{n} a_k\, b_{n-k}. \] 여기서 \( c_n \)은 \( a \)와 \( b \)의 컨벌루션(convolution)이라 부릅니다.

이 컨벌루션이 왜 카운팅을 해주냐면, “전체 무게 \( n \)을 만들 때, \( A \) 쪽에서 무게 \( k \), \( B \) 쪽에서 무게 \( n-k \)를 가져와 짝지은 경우의 수”를 각 \( k \)에 대해 더한 값이기 때문입니다. 두 결정의 합으로 만들어지는 모든 카운팅 문제가 자동으로 컨벌루션이 되는 거예요.

예제 16.2.2 (동전 거스름돈)

1원, 2원, 5원짜리 동전이 무한히 많을 때, \( n \)원을 만드는 방법의 수 \( c_n \)을 구하고 싶다고 합시다. 1원 동전을 \( i \)개, 2원 동전을 \( j \)개, 5원 동전을 \( k \)개 쓰면 \( i + 2j + 5k = n \)이 돼야 해요. 1원 동전만 봐서 “1원을 \( i \)개 쓰는 방법”의 생성함수는 \[ 1 + x + x^2 + x^3 + \cdots = \frac{1}{1-x}, \] 2원짜리는 \( 1 + x^2 + x^4 + \cdots = \frac{1}{1-x^2} \), 5원짜리는 \( \frac{1}{1-x^5} \)이 됩니다. 이 셋을 곱한 \[ C(x) = \frac{1}{(1-x)(1-x^2)(1-x^5)} \] 에서 \( x^n \) 계수가 바로 \( c_n \)이에요. 곱셈 한 번이 “세 동전을 어떻게 조합하는가”라는 카운팅을 통째로 처리해 준 셈입니다.

일반화하면 이렇습니다. 어떤 “부품” 종류 \( i \)에서 무게 \( w \)인 부품을 사용한다면 그 부품의 생성함수는 \( x^w \)이고, 같은 종류를 0개 이상 쓸 수 있다면 \( 1 + x^w + x^{2w} + \cdots = \frac{1}{1-x^w} \)입니다. 부품 종류가 여럿이면 각각의 생성함수를 곱해서 전체 카운팅 생성함수를 만들 수 있어요. 이걸 흔히 “선택의 곱은 생성함수의 곱”이라고 외우면 직관에 잘 박힙니다.

노트 — 합 vs 곱

또 하나 알아둘 규칙: 두 카운팅이 “겹치지 않는 경우의 합”이라면 생성함수도 더해집니다. 즉 합 규칙은 덧셈, 곱 규칙은 곱셈이에요. 4장의 카운팅 규칙이 그대로 함수 세계로 옮겨 온 모습입니다.

16.3 부분분수 Partial Fractions

생성함수를 곱셈으로 잘 만들었다면, 이제 거기서 “수열의 \( n \)번째 항”을 다시 꺼내야 활용도가 올라갑니다. 만약 식이 다항식의 비율 — 즉 유리식 \( \dfrac{P(x)}{Q(x)} \) — 형태라면, 부분분수 분해가 거의 만능 도구가 돼요.

정리 16.3.1 (부분분수 — 단순 극점 버전)

분모 \( Q(x) = (1 - r_1 x)(1 - r_2 x)\cdots(1 - r_d x) \)가 서로 다른 일차 인수들의 곱이고 \( \deg P < \deg Q \)라면, 적당한 상수 \( A_1, \dots, A_d \)가 유일하게 존재해서 \[ \frac{P(x)}{Q(x)} = \frac{A_1}{1 - r_1 x} + \frac{A_2}{1 - r_2 x} + \cdots + \frac{A_d}{1 - r_d x}. \] 이때 \( x^n \)의 계수는 \( A_1 r_1^n + A_2 r_2^n + \cdots + A_d r_d^n \)이 됩니다.

왜 좋냐고요? 각 항 \( \dfrac{A_i}{1 - r_i x} \)는 16.1에서 본 등비급수 \( A_i \sum_n r_i^n x^n \)이기 때문입니다. 그래서 합쳐 놓은 \( x^n \) 계수도 “여러 등비수열의 합”으로 깔끔하게 떨어져요. 카운팅 결과를 풀어쓰는 닫힌 형태(closed form)가 곧장 튀어나옵니다.

예제 16.3.2 (계수 추출 예)

\( G(x) = \dfrac{1}{(1-x)(1-2x)} \)의 \( x^n \) 계수를 구해봅시다. 부분분수로 \( \dfrac{1}{(1-x)(1-2x)} = \dfrac{A}{1-x} + \dfrac{B}{1-2x} \)로 두고 양변에 \( (1-x)(1-2x) \)를 곱하면 \( 1 = A(1-2x) + B(1-x) \). \( x = 1 \)을 대입하면 \( 1 = -A \)에서 \( A = -1 \), \( x = 1/2 \)을 대입하면 \( 1 = B \cdot \tfrac{1}{2} \)에서 \( B = 2 \). 따라서 \[ G(x) = \frac{-1}{1-x} + \frac{2}{1-2x}, \] \( x^n \)의 계수는 \( -1 + 2 \cdot 2^n = 2^{n+1} - 1 \)입니다. 어디서 본 수열이죠? 네, 비둘기집/하노이 탑 등에서 자주 등장하는 \( 2^{n+1} - 1 \)이에요.

노트 — 중근이 있을 때

분모에 \( (1 - r x)^2 \)처럼 같은 인수가 두 번 들어가면, 부분분수 항도 \( \dfrac{A}{1-rx} + \dfrac{B}{(1-rx)^2} \) 두 개가 필요합니다. 두 번째 항의 전개는 \( \sum_{n \ge 0} (n+1) r^n x^n \)이라는 점만 기억하면 똑같이 처리할 수 있어요. 중근 \( k \)개라면 \( (1-rx)^j \) 항을 \( j = 1, \dots, k \)까지 모두 모으면 됩니다.

16.4 선형점화식 풀기 Solving Linear Recurrences

드디어 이번 챕터의 하이라이트입니다. 선형점화식을 폐형으로 풀고 싶을 때 생성함수가 어떻게 작동하는지를 피보나치로 직접 따라가 봅시다.

피보나치 수열은 \( F_0 = 0,\ F_1 = 1 \), 그리고 \( n \ge 2 \)에 대해 \( F_n = F_{n-1} + F_{n-2} \)로 정의돼요. 이 수열의 생성함수를 \( F(x) = \sum_{n \ge 0} F_n x^n \)이라 두고, 점화식을 그대로 “함수의 식”으로 옮겨봅시다.

핵심 아이디어는 점화식 양변에 \( x^n \)을 곱하고 \( n \ge 2 \)에 대해 모두 더하는 것입니다. \[ \sum_{n \ge 2} F_n x^n = \sum_{n \ge 2} F_{n-1} x^n + \sum_{n \ge 2} F_{n-2} x^n. \] 좌변은 \( F(x) - F_0 - F_1 x = F(x) - x \). 우변 첫 항은 \( x \sum_{n \ge 2} F_{n-1} x^{n-1} = x(F(x) - F_0) = x F(x) \). 두 번째 항은 \( x^2 \sum_{n \ge 2} F_{n-2} x^{n-2} = x^2 F(x) \). 정리하면 \[ F(x) - x = x F(x) + x^2 F(x), \] \[ F(x)(1 - x - x^2) = x, \qquad F(x) = \frac{x}{1 - x - x^2}. \] 수열에 대한 점화식이 분모 한 줄짜리 닫힌 식으로 쪼그라들었어요.

정리 16.4.1 (피보나치 폐형 — Binet 공식)

\( \phi = \dfrac{1 + \sqrt{5}}{2} \), \( \psi = \dfrac{1 - \sqrt{5}}{2} \)라 두면, 모든 \( n \ge 0 \)에 대해 \[ F_n = \frac{1}{\sqrt{5}} \left( \phi^n - \psi^n \right). \]

증명 (생성함수 + 부분분수)

분모 \( 1 - x - x^2 \)을 인수분해해야 하는데, \( 1 - x - x^2 = (1 - \phi x)(1 - \psi x) \)임을 확인하면 됩니다. 실제로 전개하면 \( 1 - (\phi + \psi)x + \phi\psi\, x^2 \)이고, \( \phi + \psi = 1 \), \( \phi \psi = -1 \)이므로 정확히 일치해요. 이제 부분분수로 \[ F(x) = \frac{x}{(1 - \phi x)(1 - \psi x)} = \frac{A}{1 - \phi x} + \frac{B}{1 - \psi x}. \] 양변에 \( (1 - \phi x)(1 - \psi x) \)를 곱하면 \( x = A(1 - \psi x) + B(1 - \phi x) \). \( x = 1/\phi \) 대입 시 \( 1/\phi = A(1 - \psi/\phi) \), 정리하면 \( A = \dfrac{1}{\phi - \psi} = \dfrac{1}{\sqrt{5}} \). 같은 방식으로 \( B = -\dfrac{1}{\sqrt{5}} \). 그러므로 \[ F(x) = \frac{1}{\sqrt{5}}\left( \frac{1}{1 - \phi x} - \frac{1}{1 - \psi x} \right) = \frac{1}{\sqrt{5}} \sum_{n \ge 0} (\phi^n - \psi^n) x^n, \] \( x^n \)의 계수가 정확히 \( F_n = \tfrac{1}{\sqrt{5}}(\phi^n - \psi^n) \)입니다.

점화식이 무리수와 거듭제곱으로 깔끔히 표현되는 게 신기하지 않나요. \( |\psi| < 1 \)이라 \( n \)이 커질수록 \( \psi^n \)은 0에 가까워지고, 결국 \( F_n \approx \phi^n / \sqrt{5} \)라는 황금비 성장률이 자연스럽게 따라옵니다. 일반적으로 “선형동차 점화식 → GF 분모는 다항식 → 부분분수 → 등비합”이라는 한 줄 파이프라인을 기억해 두면, 어지간한 점화식은 모두 같은 방식으로 닫힌 식이 나옵니다.

16.5 형식 멱급수 Formal Power Series

여태 계속 “수렴은 신경 안 써도 된다”라는 말을 흘려 왔는데, 이제 그 약속에 책임을 져야 할 때입니다. 핵심은 우리가 다루는 대상이 “함수”가 아니라 “수열에 가방을 씌운 형식적 표현”이라는 점이에요.

정의 16.5.1 (형식 멱급수)

형식 멱급수란 단순히 무한 수열 \( (a_0, a_1, a_2, \dots) \)를 \( \sum a_n x^n \)이라는 표기로 적은 것입니다. 두 형식 멱급수의 덧셈/곱셈은 항별로 정의해요. \[ \sum a_n x^n + \sum b_n x^n = \sum (a_n + b_n)x^n, \] \[ \left(\sum a_n x^n\right)\left(\sum b_n x^n\right) = \sum_{n}\left(\sum_{k=0}^{n} a_k b_{n-k}\right) x^n. \] 이 연산들은 형식적 합/곱이라 어떤 \( x \) 값도 대입할 필요가 없습니다.

이렇게 정의하면 곱셈의 \( x^n \) 계수는 항상 유한 합이라 잘 정의됩니다. 즉 “무한히 더했는데 발산하면 어쩌지” 같은 걱정은 처음부터 발생할 자리가 없어요. \( \sum_{k=0}^n a_k b_{n-k} \)는 유한합이니까요.

그럼 \( \dfrac{1}{1-x} = \sum x^n \) 같은 등식의 의미는 뭘까요. 이건 “\( (1-x) \cdot \sum x^n = 1 \)”이라는 형식 곱 관계로 정의합니다. 좌변을 컨벌루션 정의대로 곱하면 정말 1만 남는다는 걸 손으로 확인할 수 있어요. 그러니까 \( 1/(1-x) \)는 “\( 1-x \)의 형식 곱 역원”이라는 뜻이지, “함수 \( x \mapsto 1/(1-x) \)와 일치한다”는 해석학적 주장이 아닙니다.

정리 16.5.2 (역원의 존재)

형식 멱급수 \( A(x) = \sum a_n x^n \)에 곱셈 역원 \( A(x)^{-1} \)이 존재할 필요충분조건은 \( a_0 \ne 0 \)인 것입니다.

증명 스케치

역원 \( B(x) = \sum b_n x^n \)이 존재한다면 \( A(x)B(x) = 1 \)에서 \( x^0 \) 계수 비교로 \( a_0 b_0 = 1 \), 따라서 \( a_0 \ne 0 \). 역으로 \( a_0 \ne 0 \)이라면 \( b_0 = 1/a_0 \)에서 시작해 \( x^n \)계수가 0이라는 조건 \( \sum_{k=0}^n a_k b_{n-k} = 0 \)을 \( b_n \)에 대해 풀면 \( b_n = -\dfrac{1}{a_0}\sum_{k=1}^n a_k b_{n-k} \)이라는 점화식이 나오고, 이로써 모든 \( b_n \)을 차례로 정의할 수 있습니다.

이 결과 덕분에 \( 1 - x - x^2 \) 같은 다항식도 형식 멱급수의 세계에서 안전하게 “나눌 수” 있고, 16.4에서처럼 \( \dfrac{x}{1-x-x^2} \)을 부담 없이 적을 수 있어요. 분모의 상수항이 0이 아니기 때문입니다.

마지막으로 형식적 미분도 짚고 넘어갑시다. 형식 도함수는 \( \dfrac{d}{dx}\sum a_n x^n = \sum n a_n x^{n-1} \)로 항별로 정의해요. 수렴이 어떻든 신경쓰지 않고요. 이 형식 도함수는 일반 함수 미분이 만족하는 곱 규칙, 합 규칙을 그대로 만족하기 때문에, 16.1의 \( \frac{1}{(1-x)^2} = \sum (n+1) x^n \) 같은 항등식을 “미분으로 유도”했을 때도 결과가 진짜로 옳다고 보장됩니다.

노트 — 컴퓨터과학 시각

형식 멱급수의 마음가짐은 사실 컴퓨터과학자에게 익숙합니다. 무한 스트림(infinite stream)을 머리부터 한 항씩 “지연 평가”로 만들어내는 것과 닮았어요. 곱셈 컨벌루션은 두 스트림의 누적합 합성에 해당하고, 형식적 역원은 “자기 자신의 출력 일부를 입력으로 다시 받는” 피드백 회로로 볼 수 있습니다. 이산수학과 함수형 프로그래밍이 같은 그림을 다른 언어로 그리고 있다는 게 이 단원의 마지막 메시지예요.

PART IV — 확률

17 사건과 확률공간 Events and Probability Spaces

확률은 불확실성을 다루는 수학입니다. 컴퓨터과학에서는 무작위 알고리즘을 설계하고 분석할 때, 또 평균적인 실행시간이나 데이터 구조의 기대 동작을 가늠할 때 확률이 늘 등장합니다. 이번 챕터에서는 확률이라는 모호해 보이는 개념을 어떻게 엄밀한 수학으로 길들일 수 있는지를, 유명한 문제들을 통해 차근차근 살펴봅니다. 직관이 자주 미끄러지는 영역이라 더 조심스러운 도구가 필요합니다.

17.1 거래합시다 Let's Make a Deal

1970년대 미국의 게임쇼 Let's Make a Deal에서 진행자 몬티 홀이 던진 문제는 수학자들조차 한참을 다툰 사건이었습니다. 룰은 이렇습니다. 무대 위에 문이 세 개 있고, 그중 한 문 뒤에는 자동차가, 나머지 두 문 뒤에는 염소가 들어 있습니다. 참가자가 먼저 문 하나를 고릅니다. 그러면 진행자는 남은 두 문 중에서 염소가 있는 문 하나를 열어 보여줍니다. 진행자는 어느 문에 자동차가 있는지 알고 있고, 반드시 염소가 있는 문을 고른다는 점이 중요합니다. 그리고 참가자에게 묻습니다. 고른 문을 바꾸시겠습니까, 그대로 두시겠습니까?

여기서 많은 사람의 직관은 이렇게 말합니다. 이제 문이 두 개 남았으니 자동차가 있을 확률은 절반씩이지. 바꾸든 안 바꾸든 똑같다. 하지만 이 직관은 틀렸습니다. 바꾸면 자동차를 얻을 확률이 \( \tfrac{2}{3} \)이고, 그대로 두면 \( \tfrac{1}{3} \)에 머뭅니다. 두 배 차이가 납니다.

왜 이렇게 어긋날까요? 사람들은 흔히 지금 보이는 두 문만 바라보며 대칭성을 가정해 버립니다. 그러나 진행자가 문을 여는 행위는 단순히 정보를 지운 게 아니라, 자동차가 있는 문은 절대 열지 않는다는 규칙을 통해 정보를 적극적으로 전달한 행동입니다. 이 비대칭성을 잡아내는 방법이 있어야 합니다. 다음 절에서 살펴볼 4단계 방법이 바로 그 도구입니다.

노트

이 문제는 1990년 잡지 칼럼니스트 매릴린 보스 사반트가 바꾸는 게 유리하다고 답하자, 박사학위 소지자 수백 명이 항의 편지를 보낸 사건으로도 유명합니다. 직관이 얼마나 강하게 우리를 잘못된 답으로 끌고 가는지, 동시에 확률이 왜 형식적인 도구를 필요로 하는지를 보여주는 일화입니다.

17.2 4단계 방법 The Four Step Method

확률 문제를 안전하게 푸는 정형화된 절차가 있습니다. 단계를 통째로 외우는 게 아니라, 매번 같은 순서로 머리속을 정리하는 습관이라고 보시면 됩니다.

정의 17.2.1 (4단계 방법)

임의의 확률 문제는 다음 네 단계로 해결할 수 있습니다.

(1) 표본공간 정의: 가능한 모든 결과의 집합 \( S \)를 명확히 적습니다. 보통 트리 다이어그램으로 그리면 한눈에 들어옵니다.
(2) 결과 확률 부여: 각 결과 \( \omega \in S \)에 대해 \( \Pr[\omega] \)를 정합니다. 합은 반드시 1이 되어야 합니다.
(3) 사건 식별: 우리가 관심 있는 사건 \( E \subseteq S \)를 결과들의 집합으로 적습니다.
(4) 사건 확률 계산: \( \Pr[E] = \sum_{\omega \in E} \Pr[\omega] \)로 합산합니다.

몬티홀에 적용해 봅시다. 자동차가 있는 문을 1, 2, 3 중 하나라 하고, 참가자가 처음 고른 문도 1, 2, 3 중 하나, 그리고 진행자가 여는 문도 1, 2, 3 중 하나입니다. 단순화를 위해 참가자는 항상 1번 문을 먼저 고른다고 합시다(대칭성 때문에 일반성을 잃지 않습니다).

1단계 — 표본공간. 두 단계 무작위 시행이 일어납니다. 첫째, 자동차가 1, 2, 3번 문 중 어디에 놓이는가. 둘째, 진행자가 어느 문을 여는가. 트리로 펼치면 결과는 다음과 같이 나옵니다.

  자동차 위치     진행자가 여는 문     결과
   1 (1/3) ───── 2 (1/2) ──────── (1, 2)
              └─ 3 (1/2) ──────── (1, 3)
   2 (1/3) ───── 3 (1) ────────── (2, 3)
   3 (1/3) ───── 2 (1) ────────── (3, 2)

참가자가 1번을 고른 상태에서, 자동차가 1번에 있을 때 진행자는 2번이나 3번 중 아무 데나 열 수 있으므로 각각 \( \tfrac{1}{2} \) 확률을 부여합니다. 자동차가 2번이라면 진행자는 반드시 3번을 열어야 하고(1번은 참가자가 골랐고 2번은 자동차이므로), 자동차가 3번이라면 반드시 2번을 엽니다.

2단계 — 결과 확률. 가지의 곱으로 각 결과의 확률을 매깁니다.

\( \Pr[(1,2)] = \tfrac{1}{3} \cdot \tfrac{1}{2} = \tfrac{1}{6} \), \( \Pr[(1,3)] = \tfrac{1}{6} \), \( \Pr[(2,3)] = \tfrac{1}{3} \), \( \Pr[(3,2)] = \tfrac{1}{3} \). 합은 \( 1 \)입니다.

3단계 — 사건. 우리가 알고 싶은 건 바꾸기 전략을 쓸 때 자동차를 얻는 사건입니다. 바꾸기 전략에선, 진행자가 연 문 말고 남은 다른 문으로 바꿉니다. 이 사건 \( W \)에 속하는 결과는 자동차가 1번이 아닐 때 모두입니다. 즉 \( W = \{(2,3), (3,2)\} \).

4단계 — 합산. \( \Pr[W] = \tfrac{1}{3} + \tfrac{1}{3} = \tfrac{2}{3} \). 끝입니다. 바꾸기 전략의 승률은 \( \tfrac{2}{3} \), 안 바꾸기 전략의 승률은 \( \tfrac{1}{3} \).

노트 — 직관 vs 계산

직관: 문 두 개 남았으니 50대 50. 계산: 처음 고른 문이 자동차일 확률은 \( \tfrac{1}{3} \)에 고정되어 있고, 진행자의 행동은 그 \( \tfrac{1}{3} \)을 흔들지 않는다. 따라서 나머지 한 문이 자동차일 확률이 \( \tfrac{2}{3} \)이다. 이런 종류의 어긋남은 확률에서 끝없이 등장하므로, 4단계 방법을 한번 몸에 익혀 두면 평생을 갑니다.

17.3 이상한 주사위 Strange Dice

주사위 세 개 \( A, B, C \)를 만들었다고 합시다. 보통 주사위가 아니라 면마다 다른 숫자가 적힌 특별한 주사위입니다. 두 사람이 각자 주사위를 굴려 더 큰 수가 나오는 쪽이 이깁니다. 이때 \( A \)가 \( B \)를 이길 확률이 절반을 넘는다를 \( A \succ B \)라고 적기로 합시다.

상식적으로는 이 관계가 추이적일 거라고 기대합니다. 즉 \( A \succ B \)이고 \( B \succ C \)이면 \( A \succ C \)일 거라고요. 가위바위보처럼 순환하는 일은 보통의 부등호에는 없으니까요. 그런데 잘 만든 주사위 세 개로는 \( A \succ B \succ C \succ A \)라는 가위바위보 같은 고리를 만들 수 있습니다. 이런 주사위를 비추이적 주사위라고 부릅니다.

예제 17.3.1 (에프론의 주사위)

다음 주사위를 봅시다. 모든 면은 동일한 확률 \( \tfrac{1}{6} \)로 나옵니다.

\( A = \{2, 2, 4, 4, 9, 9\} \), \( B = \{1, 1, 6, 6, 8, 8\} \), \( C = \{3, 3, 5, 5, 7, 7\} \).

\( \Pr[A > B] \)를 계산해 봅시다. \( B \)가 \( 1 \)이 나오면(확률 \( \tfrac{1}{3} \)) \( A \)는 무조건 큽니다. \( B \)가 \( 6 \)이면(확률 \( \tfrac{1}{3} \)) \( A \)는 \( 9 \)일 때만 이기므로 \( \tfrac{1}{3} \)입니다. \( B \)가 \( 8 \)이면(확률 \( \tfrac{1}{3} \)) 마찬가지로 \( A \)는 \( 9 \)일 때만 이깁니다.

\[ \Pr[A > B] = \tfrac{1}{3} \cdot 1 + \tfrac{1}{3} \cdot \tfrac{1}{3} + \tfrac{1}{3} \cdot \tfrac{1}{3} = \tfrac{1}{3} + \tfrac{2}{9} = \tfrac{5}{9}. \]

같은 식으로 \( \Pr[B > C] = \tfrac{5}{9} \), \( \Pr[C > A] = \tfrac{5}{9} \)도 나옵니다. 즉 \( A \succ B \succ C \succ A \).

왜 직관이 무너질까요? 우리는 주사위를 평균이 큰 쪽이 강한 주사위로 자동 환산하는데, 승률은 평균이 아니라 분포의 모양 전체에 의존합니다. \( A \)는 \( 9 \) 같은 큰 수에 무게가 실리지만 \( 4 \) 이하도 자주 나오고, \( B \)는 양극단 \( 1 \)과 \( 8 \)로 갈리며, \( C \)는 중간값을 모아둔 주사위입니다. 두 분포가 만났을 때 누가 자주 이기는가 하는 문제는 단일 숫자로 환원되지 않습니다.

노트

비추이적 주사위는 단순한 잡학이 아니라, 최선의 선택이라는 개념이 어떨 때 깨지는지를 보여주는 사례입니다. 게임이론, 투표 이론, 기계학습의 손실비교 등에서 비슷한 비추이성이 등장합니다. 평균만 보고 비교하지 마라가 교훈입니다.

17.4 생일 원리 The Birthday Principle

강의실에 학생 23명이 모여 있다고 합시다. 같은 생일을 가진 두 사람이 있을 확률이 얼마나 될까요? 직관은 365일 중 23명이라니, 너무 적다. 한 5%쯤?이라고 속삭이지만, 정답은 50%를 살짝 넘습니다. 학생이 23명만 모이면 이미 동률에 도달한다는 뜻입니다.

4단계 방법으로 풀어 봅시다. 표본공간은 23명 각자가 365일 중 하루를 균등하게 가질 모든 경우, 즉 \( S = [365]^{23} \)이고 결과는 길이 23인 튜플입니다. 각 결과에 동일 확률 \( 1 / 365^{23} \)을 부여합니다(단순화: 윤년·계절성 무시).

관심 사건 \( M \)은 두 명 이상이 같은 생일인 사건입니다. 이걸 직접 세기보다 여집합 \( \overline{M} \)인 모두가 다른 생일을 세는 게 훨씬 쉽습니다. 23명을 한 명씩 줄세워 생일을 정한다고 보면, 첫 사람은 365일 중 아무 날이나 가능, 두 번째는 364일, 셋째는 363일, ..., 23번째는 \( 365 - 22 = 343 \)일.

\[ \Pr[\overline{M}] = \frac{365 \cdot 364 \cdot 363 \cdots 343}{365^{23}} \approx 0.4927. \]

따라서 \( \Pr[M] = 1 - \Pr[\overline{M}] \approx 0.5073 \). 절반을 넘습니다.

일반화도 쉽습니다. 가능한 생일 종류가 \( N \)이고 사람이 \( n \)명일 때 충돌 확률이 \( \tfrac{1}{2} \)에 도달하는 \( n \)은 대략 \( n \approx 1.177 \sqrt{N} \)입니다. \( N = 365 \)면 \( n \approx 22.5 \), 우리가 본 23과 일치합니다. 핵심은 가능한 쌍의 수가 사람 수의 제곱으로 늘어난다는 점입니다.

정리 17.4.1 (생일 원리)

각각이 \( N \)개 가능 종류 중에서 균등하게 무작위로 뽑힌 \( n \)개의 항목이 있다고 하자. 두 항목이 일치할 확률 \( p \)는 다음과 같이 근사된다.

\[ p \approx 1 - \exp\!\left(-\frac{n(n-1)}{2N}\right). \]

특히 \( n \approx \sqrt{2N \ln 2} \approx 1.177\sqrt{N} \)일 때 \( p \approx \tfrac{1}{2} \)가 된다.

증명 스케치

모두 다를 확률은 \( \prod_{k=0}^{n-1}\!\left(1 - \tfrac{k}{N}\right) \)입니다. 각 항에 \( 1 - x \le e^{-x} \)를 적용하면 \( \prod_{k=0}^{n-1} e^{-k/N} = e^{-n(n-1)/(2N)} \)을 얻습니다. 여집합을 취하면 정리의 식이 나옵니다.

노트 — CS에서의 응용

해시 함수의 충돌 분석이 정확히 이 원리입니다. 해시 출력이 \( N \)가지일 때, 약 \( \sqrt{N} \)개의 입력만 해싱해도 충돌이 거의 확실해집니다. 128비트 해시면 \( N = 2^{128} \), 충돌 임계는 \( 2^{64} \) 수준. 암호학에서 생일 공격이라 부르며, 해시의 안전 자릿수를 두 배로 잡는 이유입니다.

17.5 집합론과 확률 Set Theory and Probability

지금까지 직관적으로 사용한 표본공간사건을 이제 집합론의 언어로 다시 깔끔하게 정리해 봅시다. 이게 확률공간(probability space)의 표준 정의입니다.

정의 17.5.1 (확률공간)

확률공간은 다음 두 가지로 구성됩니다.

(1) 표본공간 \( S \): 모든 가능한 결과(outcome)의 집합.
(2) 확률 함수 \( \Pr : S \to [0, 1] \): 각 결과에 0 이상 1 이하의 실수를 배정하며, \( \sum_{\omega \in S} \Pr[\omega] = 1 \).

사건은 표본공간의 부분집합 \( E \subseteq S \)이고, 그 확률은 \( \Pr[E] = \sum_{\omega \in E} \Pr[\omega] \)로 정의합니다.

이렇게 보면 사건은 곧 부분집합이고, 사건들의 연산은 그대로 집합 연산입니다. \( A \) 또는 \( B \)가 일어남은 \( A \cup B \), 둘 다 일어남은 \( A \cap B \), \( A \)는 일어나지 않음은 여집합 \( \overline{A} = S \setminus A \). 집합 항등식이 곧 확률의 항등식이 되는 강력한 사전이 생기는 셈입니다.

정리 17.5.2 (확률 측도의 기본 성질)

임의의 사건 \( A, B \subseteq S \)에 대해 다음이 성립합니다.

(a) \( \Pr[\emptyset] = 0 \), \( \Pr[S] = 1 \).
(b) \( \Pr[\overline{A}] = 1 - \Pr[A] \).
(c) 합집합 경계 (Union Bound): \( \Pr[A \cup B] \le \Pr[A] + \Pr[B] \). 일반적으로 \( \Pr\!\left[\bigcup_{i} A_i\right] \le \sum_i \Pr[A_i] \).
(d) 포함–배제: \( \Pr[A \cup B] = \Pr[A] + \Pr[B] - \Pr[A \cap B] \).
(e) 단조성: \( A \subseteq B \implies \Pr[A] \le \Pr[B] \).

증명 스케치

모두 \( \Pr[E] = \sum_{\omega \in E} \Pr[\omega] \)에서 자동으로 따라옵니다. 예컨대 (b)는 \( S = A \cup \overline{A} \)에서 \( \Pr[A] + \Pr[\overline{A}] = \Pr[S] = 1 \)이고, (c)는 \( A \cup B \)의 원소 각각이 우변에서 한 번 또는 두 번 세어진다는 데서, (d)는 두 번 세어진 \( A \cap B \)를 한 번 빼주는 데서, (e)는 \( B = A \cup (B \setminus A) \)의 분해에서 나옵니다.

합집합 경계는 거칠어 보여도 컴퓨터과학에서 가장 자주 등장하는 부등식 중 하나입니다. 가령 무작위 알고리즘이 \( m \)가지 나쁜 사건 중 어느 하나라도 발생하면 실패한다고 합시다. 각 나쁜 사건의 확률을 \( \tfrac{1}{m^2} \) 이하로 누를 수 있다면 합집합 경계로 전체 실패 확률은 \( \tfrac{1}{m} \)을 넘지 않습니다. 정확한 \( \Pr[A_i \cap A_j] \)을 몰라도 위쪽 경계만 잡고 안전하게 결론을 내릴 수 있는 도구입니다.

예제 17.5.3 (몬티홀 다시 보기)

17.2절에서 표본공간 \( S = \{(1,2),(1,3),(2,3),(3,2)\} \), 확률 \( \tfrac{1}{6}, \tfrac{1}{6}, \tfrac{1}{3}, \tfrac{1}{3} \), 사건 \( W = \{(2,3),(3,2)\} \)을 정했습니다. 이는 정의 17.5.1을 충족합니다(확률 합 \( = 1 \), \( W \subseteq S \)). 따라서 \( \Pr[W] = \tfrac{2}{3} \)는 단순한 트릭이 아니라 잘 정의된 확률공간 위에서의 정직한 계산입니다.

노트 — 무한 표본공간에 대해서

이번 챕터에서는 \( S \)가 유한하거나 셀 수 있는 경우만 다룹니다. 실수 구간처럼 셀 수 없는 표본공간을 엄밀히 다루려면 측도론(measure theory)이 필요해집니다. 다행히 컴퓨터과학에서 만나는 대부분의 확률 모형은 유한이라, 우리에게 필요한 도구는 사실상 다 갖춘 셈입니다.

이렇게 사건을 집합으로, 확률을 측도로 보는 시점이 자리잡으면, 다음 챕터들에서 다룰 조건부 확률·독립성·기댓값·집중 부등식이 모두 같은 언어 위에서 자연스럽게 펼쳐집니다. 확률은 더 이상 이 아니라, 우리가 5장과 8장에서 길러 온 집합과 합산의 도구를 그대로 다시 쓰는 분야가 되는 것입니다.

PART IV — 확률

18 조건부 확률 Conditional Probability

정보가 추가되면 확률이 바뀝니다. 어제까지 비올 확률 30%였던 하늘이 먹구름을 보이는 순간 80%가 되는 것처럼요. 이 챕터에서는 "어떤 사건이 이미 일어났다는 정보"를 받았을 때 확률이 어떻게 갱신되는지를 다루는 도구, 조건부 확률을 배웁니다. 정의는 한 줄이지만 이걸 잘못 다루면 멀쩡한 사람도 몬티홀 문제 앞에서 무너지죠. 트리 다이어그램, 전확률 법칙, 베이즈 정리, 그리고 직관을 박살내는 심슨의 역설까지 가봅시다.

18.1 몬티홀의 혼란 Monty Hall Confusion

문 셋 중 하나 뒤에는 자동차가, 나머지 둘 뒤에는 염소가 있습니다. 참가자가 한 문을 고르면, 정답을 아는 사회자 몬티가 나머지 두 문 중 염소가 있는 문 하나를 열어 보여줍니다. 그리고 묻습니다. "바꾸시겠어요?" 직관은 "둘 중 하나니까 50:50, 바꾸나 안 바꾸나 똑같다"고 말합니다. 그런데 이게 틀렸어요. 바꾸면 \( 2/3 \), 안 바꾸면 \( 1/3 \) 입니다.

왜 직관이 무너질까요? 몬티가 문을 여는 행동이 정보를 뿌리기 때문입니다. 그는 무작위로 문을 열지 않고, "염소가 있고, 참가자가 고르지 않은" 문을 골라서 엽니다. 이 조건이 확률 분포를 비대칭으로 휘게 만들어요. 14장에서 이미 이 문제를 한 번 풀었지만, 그땐 표본공간을 직접 펼쳐서 셌습니다. 이번엔 더 강력한 도구로 봅니다.

노트 18.1.1

조건부 확률의 핵심 질문은 "B가 일어났다는 사실을 알았을 때, A의 확률은?"입니다. "그냥 A의 확률"과는 다른 양이에요. 정보가 들어오면 표본공간이 사실상 좁아지고, 그 좁아진 세계 안에서 다시 비율을 재는 거예요.

몬티홀에서 "바꿨을 때 자동차를 얻을 확률"은 결국 "참가자가 처음에 염소를 골랐을 확률"과 같습니다. 처음 추측이 틀릴 확률 \( 2/3 \) 가 그대로 정답률로 돌아오는 거예요. 이 챕터를 마칠 즈음에는 이 한 줄이 자연스럽게 들리길 바랍니다.

18.2 정의와 표기 Definition and Notation

조건부 확률은 표기법부터 익숙해지면 좋아요. \( P(A \mid B) \) 는 "B가 일어났다는 가정 하에서 A의 확률"이고, 읽을 땐 "P of A given B"라고 합니다. 정의는 다음과 같습니다.

정의 18.2.1 (조건부 확률)

표본공간 \( \Omega \) 위의 확률측도 \( P \) 와 \( P(B) > 0 \) 인 사건 \( B \) 가 주어졌을 때,

\[ P(A \mid B) \;=\; \frac{P(A \cap B)}{P(B)}. \]

\( P(B) = 0 \) 일 때는 정의되지 않습니다.

식의 모양을 직관적으로 풀어볼게요. 분모 \( P(B) \) 가 새로운 표본공간(B 안에서 다시 비율을 재겠다는 의미)이고, 분자 \( P(A \cap B) \) 가 그 안에서 A도 함께 일어나는 부분의 크기입니다. B를 새 1로 두고 거기서 A가 차지하는 비율을 다시 계산하는 셈이에요.

예제 18.2.2 (주사위 두 개)

공정한 주사위 두 개를 굴립니다. \( A \) = "합이 7", \( B \) = "첫 번째가 짝수"라 하면 \( P(A) = 6/36 = 1/6 \), \( P(B) = 1/2 \), \( P(A \cap B) = 3/36 = 1/12 \) 입니다. 따라서 \( P(A \mid B) = (1/12) / (1/2) = 1/6 \). 신기하게도 정보가 추가됐는데 확률이 안 바뀌었어요. 이런 경우 두 사건은 독립이라고 부르는데, 곧 18.7에서 다룹니다.

반대로 \( B' \) = "첫 번째가 1"로 바꾸면 \( P(B') = 1/6 \), \( P(A \cap B') = 1/36 \) 이라 \( P(A \mid B') = 1/6 \). 어, 또 같네요? 합이 7은 첫 번째 눈이 무엇이든 두 번째가 정확히 한 값으로 정해지므로 \( 1/6 \) 이 유지되는 거예요. 이런 부분이 확률의 재미있는 점입니다.

18.3 조건부 확률에서의 4단계 방법 The Four-Step Method for Conditional Probability

복잡한 확률 문제는 다음 4단계를 따라가면 거의 풀립니다. (1) 표본공간을 트리로 펼치기, (2) 각 가지에 결과 적기, (3) 가지마다 조건부확률 적기, (4) 묻는 사건의 확률을 더하기. 트리 다이어그램은 이 절차의 시각적 도구예요.

예제 18.3.1 (몬티홀, 트리로 풀기)

자동차의 위치는 1, 2, 3 중 균등(각 \( 1/3 \)). 참가자는 항상 문 1을 고른다고 가정합시다(대칭이므로 일반성 잃지 않음). 몬티는 자동차 없는 문 중 하나를 엽니다. 자동차가 1번에 있으면 2번 또는 3번을 동률로 선택, 2번에 있으면 3번만, 3번에 있으면 2번만 엽니다. 마지막으로 참가자는 "바꾼다"는 전략을 씁니다.

트리의 잎(leaf)에서 "최종적으로 자동차를 얻었나?"를 표시하고, 각 잎의 확률을 가지 확률의 곱으로 계산해 잎들의 확률을 더하면 답이에요. 자동차가 처음부터 1번이었던 가지(확률 \( 1/3 \))에서는 바꾸면 무조건 실패, 2번 또는 3번이었던 가지(각 \( 1/3 \))에서는 바꾸면 무조건 성공입니다. 따라서 성공 확률은 \( 2/3 \).

여기서 핵심은 가지에 적힌 숫자들이 모두 조건부확률이라는 사실이에요. "자동차가 1번이라는 조건 하에서 몬티가 2번을 열 확률은 \( 1/2 \)" 같은 식. 이 가지들을 곱해야 그 잎이 발생할 확률이 됩니다. 왜 곱셈이 맞는지는 다음 절에서 정당화합니다.

18.4 트리 다이어그램이 작동하는 이유 Why Tree Diagrams Work

트리에서 가지를 곱해 잎의 확률을 얻는 절차는, 사실 정의 18.2.1을 단순히 변형한 것입니다. 양변에 \( P(B) \) 를 곱하면

원리 18.4.1 (곱셈 규칙)

\( P(B) > 0 \) 인 사건 \( B \) 와 임의의 \( A \) 에 대해 \[ P(A \cap B) \;=\; P(B) \cdot P(A \mid B). \] 더 일반적으로, 사건 \( A_1, A_2, \dots, A_n \) 에 대해 \[ P(A_1 \cap A_2 \cap \dots \cap A_n) \;=\; P(A_1) \cdot P(A_2 \mid A_1) \cdot P(A_3 \mid A_1 \cap A_2) \cdots P(A_n \mid A_1 \cap \dots \cap A_{n-1}). \]

트리의 한 경로는 정확히 \( A_1 \cap A_2 \cap \dots \cap A_n \) 의 형태입니다. 첫 가지는 \( P(A_1) \), 그 다음 가지는 "\( A_1 \) 이 일어났다는 조건 하에서 \( A_2 \)" 즉 \( P(A_2 \mid A_1) \), 그 다음은 \( P(A_3 \mid A_1 \cap A_2) \), 이런 식이에요. 이 가지들을 다 곱하면 정확히 위 공식이 나옵니다.

예제 18.4.2 (카드 두 장)

섞인 카드 52장에서 두 장을 비복원으로 뽑습니다. 둘 다 에이스일 확률은? \( P(\text{1번째 A}) = 4/52 \), \( P(\text{2번째 A} \mid \text{1번째 A}) = 3/51 \). 곱하면 \( (4/52)(3/51) = 12/2652 = 1/221 \). 가지가 두 단계인 트리를 그렸다고 보면 됩니다.

트리는 그저 직관적인 그림이 아니라, 곱셈 규칙의 시각적 표현이에요. 어떤 복잡한 문제든 결과를 단계로 쪼갤 수 있다면 트리로 옮길 수 있고, 옮긴 순간 답은 산수 문제로 바뀝니다.

18.5 전확률 법칙 The Law of Total Probability

표본공간을 서로소인 사건들 \( B_1, B_2, \dots, B_n \) 으로 빈틈없이 쪼갤 수 있다면(이를 분할이라 합니다), 어떤 사건 \( A \) 의 확률은 각 조각을 통과하는 경로들의 합으로 적을 수 있어요.

정리 18.5.1 (전확률 법칙, Law of Total Probability)

\( B_1, \dots, B_n \) 이 \( \Omega \) 의 분할이고 모든 \( i \) 에 대해 \( P(B_i) > 0 \) 이면, \[ P(A) \;=\; \sum_{i=1}^{n} P(A \mid B_i) \, P(B_i). \]

이 식과 정의 18.2.1을 결합하면 그 유명한 베이즈 정리가 떨어집니다.

정리 18.5.2 (베이즈 정리, Bayes' Theorem)

\( P(A), P(B) > 0 \) 일 때 \[ P(B \mid A) \;=\; \frac{P(A \mid B) \, P(B)}{P(A)} \;=\; \frac{P(A \mid B) \, P(B)}{\sum_i P(A \mid B_i) \, P(B_i)}. \]

예제 18.5.3 (희귀병 검사)

인구의 \( 1\% \) 가 어떤 병에 걸려 있다고 하죠. 검사는 환자에게서 \( 99\% \) 확률로 양성이 나오고, 건강한 사람에게서도 \( 5\% \) 확률로 양성이 나옵니다(위양성). 어떤 사람이 양성을 받았을 때 실제로 병에 걸렸을 확률은?

\( D \) = 병, \( T \) = 양성. \( P(D)=0.01, P(T \mid D)=0.99, P(T \mid D^c)=0.05 \). 전확률로 \( P(T) = 0.99 \cdot 0.01 + 0.05 \cdot 0.99 = 0.0099 + 0.0495 = 0.0594 \). 베이즈로 \( P(D \mid T) = 0.99 \cdot 0.01 / 0.0594 \approx 0.167 \). 약 17%예요. 검사 정확도가 99%라는데 양성이어도 실제 환자일 확률이 17%밖에 안 된다는 게 충격적이죠. 희귀할수록 위양성의 영향이 크다는 교훈입니다.

18.6 심슨의 역설 Simpson's Paradox

직관에 가장 통쾌한 한 방을 날리는 카드입니다. 두 그룹 각각에서 X가 Y보다 좋은데, 합치면 Y가 X보다 좋다. "어떻게 그럴 수가?" 싶지만, 실제 통계에서 자주 발생합니다.

예제 18.6.1 (가상의 대학원 입학)

한 대학원이 학과 X와 Y에 지원자를 받습니다. 학과별 성별 합격률은 아래와 같다고 하죠.

학과남자 지원/합격남자 합격률여자 지원/합격여자 합격률
X (인기)400 / 8020%100 / 3030%
Y (한산)100 / 7070%400 / 32080%
합계500 / 15030%500 / 35070%

학과별로는 두 곳 모두 여자 합격률이 더 높은데, 합치면? 30% vs 70%. 어, 이건 여자가 훨씬 유리해 보이네요. 값을 살짝 바꿔서 정반대 결론도 만들 수 있습니다 — 이게 심슨 역설의 본질이에요. 핵심은 여자들이 합격률 높은 학과(Y)에 몰려 지원했다는 점. 그룹 크기의 차이가 평균을 휘게 만들어요.

의료 통계에서도 흔합니다. 신약이 모든 연령대에서 위약보다 잘 듣는데 전체로 보면 위약이 이기는 경우가 있어요. 연령대별 환자 수가 달라서요. 핵심 교훈: 조건부 확률을 통합할 땐 분할의 가중치를 함께 봐야 한다. \( P(A \mid B_1) > P(A' \mid B_1) \) 이고 \( P(A \mid B_2) > P(A' \mid B_2) \) 라 해도 가중치 \( P(B_i) \) 가 양쪽에서 다르면 \( P(A) \) 와 \( P(A') \) 의 부등호는 뒤집힐 수 있습니다.

노트 18.6.2

실세계에서 데이터가 "전체 평균"으로만 제시될 때 의심해 볼 줄 알아야 합니다. 적절한 분할을 들이대면 스토리가 완전히 뒤집히기도 해요. 컴퓨터과학에서 A/B 테스트 결과를 해석할 때도 같은 함정이 있습니다.

18.7 독립 Independence

"정보를 받아도 확률이 안 바뀌는" 사건들을 독립이라고 합니다. 18.2의 주사위 예제에서 \( P(A \mid B) = P(A) \) 가 그런 경우였죠. 정의는 깔끔합니다.

정의 18.7.1 (두 사건의 독립)

사건 \( A, B \) 가 독립이라는 것은 \[ P(A \cap B) \;=\; P(A) \, P(B). \] \( P(B) > 0 \) 이면 이는 \( P(A \mid B) = P(A) \) 와 동치입니다.

"확률이 0인 사건은 어떻게 되나?" 같은 경계 사례를 깔끔히 처리하려고 곱 형태를 정의로 채택해요. 직관적으로 독립은 "한쪽이 일어났다는 사실이 다른 쪽의 분포에 아무 영향을 못 준다"는 의미입니다.

예제 18.7.2 (동전 두 번)

공정한 동전을 두 번 던집니다. \( H_1 \) = "첫 번째가 앞", \( H_2 \) = "두 번째가 앞". 각 \( 1/2 \) 이고 \( P(H_1 \cap H_2) = 1/4 \). 곱과 같으니 독립이에요. 반면 같은 실험에서 \( S \) = "둘 다 같은 면", \( H_1 \) 을 비교해 보세요. \( P(S) = 1/2, P(H_1) = 1/2, P(S \cap H_1) = 1/4 \). 신기하게도 이쪽도 독립입니다.

주의할 점: 서로소(disjoint)와 독립(independent)은 완전히 다른 개념입니다. 서로소면 \( P(A \cap B) = 0 \) 인데, \( A, B \) 가 둘 다 양의 확률이면 곱은 양수라 정의 18.7.1을 만족할 수 없어요. 서로소인 두 양수확률 사건은 절대 독립이 아닙니다.

18.8 상호 독립 Mutual Independence

여러 사건의 독립은 한 단계 더 까다롭습니다. 단순히 "두 개씩 짝지어 모두 독립"인 것(쌍별 독립, pairwise)과 "모든 부분집합이 독립"인 것(상호 독립, mutual)은 다릅니다.

정의 18.8.1 (상호 독립)

사건 \( A_1, A_2, \dots, A_n \) 이 상호 독립이라는 것은, 임의의 부분집합 \( \{i_1, i_2, \dots, i_k\} \subseteq \{1, \dots, n\} \) 에 대해 \[ P(A_{i_1} \cap A_{i_2} \cap \dots \cap A_{i_k}) \;=\; P(A_{i_1}) \, P(A_{i_2}) \cdots P(A_{i_k}). \]

예제 18.8.2 (쌍별인데 상호는 아님)

공정한 동전 두 개를 던집니다. \( A \) = "첫 번째 앞", \( B \) = "두 번째 앞", \( C \) = "두 결과가 같음". 각 확률은 \( 1/2 \) 이고, 어떤 둘을 골라도 교집합 확률은 \( 1/4 \) 라 쌍별 독립입니다. 그런데 \( A \cap B \cap C = A \cap B \) 라 \( P(A \cap B \cap C) = 1/4 \neq 1/8 = P(A)P(B)P(C) \). 세 개 모두 모이면 독립이 깨지는 거예요.

쉽게 말해 쌍별 독립은 "어느 한 사건에 대한 정보로는 다른 한 사건을 못 맞추지만, 두 사건의 정보를 합치면 세 번째를 알 수도 있다"는 상황을 허용합니다. 진짜 독립을 원하면 부분집합 모두를 점검해야 해요.

노트 18.8.3

실무에서 \( n \) 개의 사건이 상호 독립이면 결합확률이 \( P(A_1) \cdots P(A_n) \) 으로 깔끔히 분해되어 계산이 폭발적으로 단순해집니다. 통신 채널에서의 비트 오류, 네트워크 패킷 손실, 분산 시스템의 노드 장애 같은 모델링이 보통 이 가정 위에서 굴러가요. 단, 이 가정이 깨지는 순간(전원 동시 다운, 같은 라우터 의존) 시스템이 한꺼번에 무너집니다.

18.9 확률 vs 신뢰도 Probability versus Confidence

마지막으로 철학적인 곁가지 하나. "동전을 던졌을 때 앞이 나올 확률 \( 1/2 \)"라는 말은 무슨 뜻일까요? 답이 둘로 갈립니다.

빈도주의(frequentist) 관점: 확률은 "장기적으로 같은 실험을 무한히 반복했을 때의 빈도"입니다. 앞면이 나올 확률이 \( 1/2 \) 라는 건 던지기를 무한히 하면 앞면 비율이 \( 1/2 \) 로 수렴한다는 뜻이에요. 이 관점에서 "내일 비올 확률이 30%"는 다소 어색합니다. 내일은 한 번뿐이라 빈도가 정의되지 않으니까요.

베이즈주의(Bayesian) 관점: 확률은 "관찰자의 신뢰도(degree of belief)"입니다. 30%란 "내가 가진 정보로 봤을 때 비가 올 거라는 믿음의 강도가 그 정도"라는 의미예요. 새 정보가 들어오면 베이즈 정리로 신뢰도를 업데이트합니다(사전 확률 → 사후 확률).

노트 18.9.1 (어떤 관점이 맞나?)

둘 다 맞습니다. 다만 응용 영역이 달라요. 동전이나 주사위처럼 반복 가능한 현상에는 빈도주의가 자연스럽고, 의학 진단·머신러닝·일기예보처럼 "한 번뿐인 사건에 신뢰도를 매기는" 상황에는 베이즈가 강력합니다. 흥미롭게도 두 관점 모두 정의 18.2.1과 정리 18.5.2를 그대로 사용해요. 수학은 같고 해석만 다릅니다.

베이즈 정리를 다시 봅시다. \( P(B \mid A) = P(A \mid B) P(B) / P(A) \). 베이즈 관점에서 \( P(B) \) 는 사전 신뢰도(prior), \( P(B \mid A) \) 는 \( A \) 라는 증거를 본 뒤의 사후 신뢰도(posterior), \( P(A \mid B) \) 는 가설 \( B \) 가 데이터 \( A \) 를 얼마나 잘 설명하는지를 나타내는 가능도(likelihood)입니다. 이 세 단어는 통계학·머신러닝의 기본 어휘예요.

이 챕터에서 우리는 "정보가 들어오면 확률이 바뀐다"는 한 줄을 정의 18.2.1로 엄밀화하고, 그것이 트리·전확률·베이즈·심슨역설·독립 같은 풍성한 결과로 뻗어가는 모습을 봤습니다. 다음 챕터에서는 확률을 값으로 다루는 도구, 확률변수로 넘어갑니다. 이제 사건 단위가 아니라 숫자 단위로 확률을 보는 거예요.

PART IV — 확률

19 확률변수 Random Variables

앞 챕터들에서 우리는 표본공간 위에서 사건(event)의 확률을 계산했어요. 그런데 막상 문제를 풀다 보면 "어느 사건이 일어났는가"보다 "어떤 수치가 나왔는가"가 더 궁금할 때가 많습니다. 주사위 두 개의 합, 동전 \(n\)번 던졌을 때 앞면의 개수, 랜덤 알고리즘의 비교 횟수 — 모두 표본공간 위에 정의된 "수치 함수"입니다. 이 함수가 바로 확률변수예요. 이 챕터에서는 확률변수와 그 분포를 정의하고, 기댓값이라는 강력한 도구, 그리고 거의 마법처럼 작동하는 기댓값의 선형성을 다룹니다.

19.1 확률변수 예 Random Variable Examples

표본공간 \(S\)가 정해졌다고 합시다. 우리는 결과 \(\omega \in S\) 하나하나에 어떤 실수를 대응시키고 싶어요. 예를 들어 동전 세 번을 던지는 실험이라면 결과는 HHT, THH 같은 문자열인데, 우리가 정말 알고 싶은 건 "앞면이 몇 번 나왔는가"라는 숫자입니다. 그러니 결과를 숫자로 보내주는 함수가 필요합니다.

정의 19.1.1 (확률변수)

표본공간 \(S\) 위의 확률변수(random variable)는 함수 \(X : S \to \mathbb{R}\) 입니다. 즉 각 결과 \(\omega \in S\)에 실수 \(X(\omega)\)를 대응시키는 함수예요.

이름은 "변수"지만, 실체는 함수입니다. 이게 처음 헷갈리는 부분이에요. 보통 변수라 하면 \(x = 3\) 같은 정해진 값이 떠오르지만, 확률변수 \(X\)는 "결과에 따라 다른 값을 내놓는 규칙"입니다. 결과 \(\omega\)가 정해지면 \(X(\omega)\)도 정해져요. 결과가 무작위니까 \(X\)의 값도 무작위가 됩니다.

예제 19.1.2 (주사위 두 개의 합)

공정한 6면체 주사위 두 개를 던집니다. 표본공간은 \(S = \{(i,j) : 1 \le i, j \le 6\}\), 크기 36이고 각 결과의 확률은 \(1/36\)입니다. 확률변수 \(T(\omega) = i + j\) 를 "두 주사위 눈의 합"으로 정의해요. 그러면 \(T\)는 2부터 12까지의 값을 갖습니다. 예컨대 \(\omega = (3,4)\)이면 \(T(\omega) = 7\), \(\omega = (6,6)\)이면 \(T(\omega) = 12\)입니다. \(T = 7\)이 되는 결과는 \((1,6), (2,5), (3,4), (4,3), (5,2), (6,1)\)로 6가지이니, \(\Pr[T=7] = 6/36 = 1/6\) 입니다.

예제 19.1.3 (동전 던지기의 앞면 수)

공정한 동전을 \(n\)번 독립적으로 던집니다. 표본공간 \(S = \{H, T\}^n\), 각 결과의 확률은 \(1/2^n\)입니다. 확률변수 \(H_n(\omega)\)를 "결과 \(\omega\)에 들어 있는 H의 개수"로 정의하면, \(H_n\)은 0부터 \(n\)까지의 값을 가져요. \(\Pr[H_n = k] = \binom{n}{k}/2^n\) 입니다.

한 가지 더 짚어둘 게 있어요. 같은 표본공간 위에 여러 확률변수를 동시에 정의할 수 있습니다. 주사위 두 개의 예에서 \(T\)는 합, \(D(\omega) = |i - j|\)는 차이의 절댓값, \(M(\omega) = \max(i,j)\)는 최댓값 — 이런 식으로 얼마든지요. 모두 같은 \(\omega\)에서 동시에 평가될 수 있고, 그래서 \(T\)와 \(M\)이 함께 어떻게 움직이는지(공분산 같은 것)를 따질 수 있게 됩니다.

노트 (인디케이터 변수)

특별히 자주 쓰는 확률변수가 인디케이터(indicator) 확률변수입니다. 사건 \(A \subseteq S\)에 대해 \(I_A(\omega) = 1\) (만약 \(\omega \in A\)), \(0\) (그렇지 않으면). 0/1 값만 갖는 확률변수예요. 매우 단순해 보이지만, 19.5절의 마법은 사실상 이 인디케이터 트릭에서 옵니다.

19.2 독립 Independence

사건의 독립은 이미 봤어요: \(\Pr[A \cap B] = \Pr[A] \cdot \Pr[B]\). 확률변수의 독립은 이것의 자연스러운 확장입니다. 두 확률변수가 독립이라는 건, 한쪽 값을 알아도 다른 쪽 값에 대한 우리 예측이 바뀌지 않는다는 뜻이에요.

정의 19.2.1 (확률변수의 독립)

확률변수 \(X, Y\)가 독립이라는 것은 \(X, Y\)가 가질 수 있는 임의의 값 \(x, y\)에 대해 \[\Pr[X = x \text{ 그리고 } Y = y] = \Pr[X = x] \cdot \Pr[Y = y]\] 가 성립한다는 뜻입니다. 더 일반적으로 \(X_1, \ldots, X_n\)이 (상호) 독립이라는 것은 임의의 값 \(x_1, \ldots, x_n\)에 대해 \(\Pr[X_1 = x_1, \ldots, X_n = x_n] = \prod_{i=1}^{n} \Pr[X_i = x_i]\) 입니다.

예제 19.2.2 (독립인 경우와 아닌 경우)

주사위 두 개를 던질 때, \(X_1\)을 첫 번째 눈, \(X_2\)를 두 번째 눈이라 하면 \(X_1, X_2\)는 독립입니다. 어떤 \(a, b \in \{1,\ldots,6\}\)에 대해서도 \(\Pr[X_1 = a, X_2 = b] = 1/36 = (1/6)(1/6)\)이니까요. 반면 같은 실험에서 \(T = X_1 + X_2\)와 \(X_1\)은 독립이 아닙니다. 예를 들어 \(X_1 = 1\)이라는 정보를 얻으면 \(T\)는 절대 12가 될 수 없잖아요. 사전엔 \(\Pr[T=12] = 1/36\)이지만 \(X_1=1\)을 안 뒤엔 0으로 바뀝니다.

독립은 좋은 성질이에요. 독립이면 결합 확률을 분해할 수 있고, 분산이 합으로 분리되고(20장에서 확인), 큰 수의 법칙·중심극한정리 같은 것이 깔끔하게 작동합니다. 그런데 한 가지 큰 사실: 기댓값의 선형성은 독립을 요구하지 않아요. 19.5절에서 다시 말씀드릴게요.

19.3 분포 함수 Distribution Functions

확률변수 \(X\)에 대해 우리가 알고 싶은 모든 정보는 결국 "\(X\)가 어떤 값을 얼마의 확률로 갖는가"로 요약됩니다. 이 정보를 담는 함수가 분포(distribution)예요. 이산확률변수에서는 두 가지 방식이 표준입니다.

정의 19.3.1 (PMF, CDF)

이산확률변수 \(X\)의 확률질량함수(probability mass function, PMF)는 \(p_X(x) = \Pr[X = x]\) 입니다. 누적분포함수(cumulative distribution function, CDF)는 \(F_X(x) = \Pr[X \le x]\) 입니다. 두 함수는 서로의 정보를 모두 담고 있어요: \(p_X(x) = F_X(x) - F_X(x^-)\), \(F_X(x) = \sum_{y \le x} p_X(y)\).

PMF는 항상 \(\sum_x p_X(x) = 1\)을 만족하고 \(0 \le p_X(x) \le 1\)이어야 합니다. CDF는 비감소 함수이며 \(\lim_{x \to -\infty} F_X(x) = 0\), \(\lim_{x \to \infty} F_X(x) = 1\) 입니다. 자주 만나는 분포들을 정리해 둘게요.

정의 19.3.2 (베르누이 분포)

모수 \(p \in [0,1]\)의 베르누이 분포는 \(\Pr[X=1] = p, \Pr[X=0] = 1-p\) 인 분포입니다. "한 번의 동전 던지기" 같은, 0/1 결과의 가장 단순한 모형이에요. 표기는 \(X \sim \mathrm{Bern}(p)\).

정의 19.3.3 (이항 분포)

모수 \(n, p\)의 이항 분포는 독립적인 베르누이 \(p\) 시행 \(n\)번에서 성공 횟수의 분포입니다. PMF는 \[\Pr[X = k] = \binom{n}{k} p^k (1-p)^{n-k}, \quad k = 0, 1, \ldots, n.\] 표기는 \(X \sim \mathrm{Bin}(n, p)\). 동전 \(n\)번 던졌을 때 앞면 수 \(H_n\)은 \(\mathrm{Bin}(n, 1/2)\)예요.

정의 19.3.4 (기하 분포)

모수 \(p \in (0,1]\)의 기하 분포는 독립적인 베르누이 \(p\) 시행에서 첫 성공이 나올 때까지의 시행 횟수입니다. PMF는 \[\Pr[X = k] = (1-p)^{k-1} p, \quad k = 1, 2, 3, \ldots\] 표기는 \(X \sim \mathrm{Geo}(p)\). "버그가 나오기까지 몇 번째 빌드?" 같은 질문에 자연스러운 모형이에요.

정의 19.3.5 (이산 균등 분포)

유한 집합 \(\{a_1, \ldots, a_n\}\) 위의 균등 분포는 모든 값을 똑같이 \(1/n\)의 확률로 가집니다. 주사위 한 번 던지기는 \(\{1, \ldots, 6\}\) 위의 균등 분포예요.

예제 19.3.6 (이항 PMF 작은 예)

\(X \sim \mathrm{Bin}(4, 1/2)\)일 때 PMF를 계산해 봅시다. 분모가 \(2^4 = 16\)이고 분자가 \(\binom{4}{k}\)예요.

\(k\)01234
\(\Pr[X=k]\)1/164/166/164/161/16

합쳐 보면 \(1/16 + 4/16 + 6/16 + 4/16 + 1/16 = 16/16 = 1\)이고, 가운데인 \(k=2\)에서 가장 큽니다. 이항계수의 종 모양이 그대로 보이죠.

노트 (결합 분포)

두 확률변수 \(X, Y\)에 대한 정보를 함께 담으려면 결합 PMF \(p_{X,Y}(x,y) = \Pr[X=x, Y=y]\)를 봅니다. 결합 분포에서 \(y\)에 대해 합치면 주변 분포 \(p_X(x) = \sum_y p_{X,Y}(x,y)\)가 나오고요. 19.2절의 독립 조건은 정확히 \(p_{X,Y}(x,y) = p_X(x) p_Y(y)\)와 같은 말입니다.

19.4 큰 기대 Great Expectations

분포 전체를 볼 수 있다면 좋겠지만, 보통 우리는 그 분포를 한두 개의 숫자로 요약하고 싶어요. 그중 가장 중요한 게 기댓값(expected value), 즉 평균입니다. "이 확률변수의 값은 평균적으로 얼마쯤 될까?"에 답하는 양이에요.

정의 19.4.1 (기댓값)

이산확률변수 \(X\)의 기댓값은 \[\mathrm{E}[X] = \sum_{x} x \cdot \Pr[X = x] = \sum_{\omega \in S} X(\omega) \cdot \Pr[\omega]\] 로 정의됩니다(합이 절대수렴할 때). 두 표현은 같은 값을 줘요. 첫 번째는 "값 × 확률을 그 값을 갖는 결과들로 묶어 합산"이고, 두 번째는 "결과별 기여를 그대로 합산"입니다.

예제 19.4.2 (공정한 주사위)

\(X\)를 공정한 6면체 주사위의 눈이라 하면 \[\mathrm{E}[X] = 1 \cdot \tfrac{1}{6} + 2 \cdot \tfrac{1}{6} + \cdots + 6 \cdot \tfrac{1}{6} = \tfrac{1+2+3+4+5+6}{6} = \tfrac{21}{6} = 3.5\] 입니다. 주사위에는 3.5라는 눈이 없지만, "평균"은 그 사이 어딘가에 있어도 괜찮아요.

예제 19.4.3 (인디케이터 트릭)

인디케이터 변수 \(I_A\)의 기댓값을 봅시다. \(I_A\)는 1 (\(\omega \in A\))과 0 (\(\omega \notin A\)) 두 값만 갖죠. \[\mathrm{E}[I_A] = 1 \cdot \Pr[A] + 0 \cdot \Pr[A^c] = \Pr[A].\] 그러니까 인디케이터의 기댓값은 그냥 사건의 확률입니다. 단순한 사실이지만, 이게 19.5절에서 보여드릴 마법의 핵심 재료예요.

예제 19.4.4 (기하 분포의 기댓값)

\(X \sim \mathrm{Geo}(p)\)일 때 \(\mathrm{E}[X]\)는 얼마일까요? 정의대로 쓰면 \[\mathrm{E}[X] = \sum_{k=1}^{\infty} k (1-p)^{k-1} p.\] 이 합은 미분 트릭으로 처리할 수 있어요. \(\sum_{k=0}^{\infty} q^k = \frac{1}{1-q}\)를 \(q\)로 미분하면 \(\sum_{k=1}^{\infty} k q^{k-1} = \frac{1}{(1-q)^2}\). 따라서 \(\mathrm{E}[X] = p \cdot \frac{1}{(1-(1-p))^2} = p \cdot \frac{1}{p^2} = \frac{1}{p}\) 입니다. "성공 확률이 \(1/6\)이면 평균 6번 만에 성공" — 직관과 잘 맞죠.

기댓값은 결과별 가중평균이라는 점에서 무게중심으로 비유하면 좋아요. PMF를 막대그래프로 그렸을 때, 그 막대들의 균형점이 \(\mathrm{E}[X]\)입니다. 그래서 분포가 한쪽으로 치우치면 기댓값도 그쪽으로 끌려가요.

정의 19.4.5 (조건부 기댓값)

사건 \(A\) (\(\Pr[A] > 0\))가 주어졌을 때 \(X\)의 조건부 기댓값은 \[\mathrm{E}[X \mid A] = \sum_{x} x \cdot \Pr[X = x \mid A]\] 로 정의합니다. 이건 "\(A\)가 일어났다는 조건 하에서의 평균"이에요. 표본공간을 사건들로 분할하면 전체 기댓값 법칙이 성립합니다: \(S = A_1 \sqcup \cdots \sqcup A_k\)일 때 \(\mathrm{E}[X] = \sum_i \mathrm{E}[X \mid A_i] \Pr[A_i]\).

전체 기댓값 법칙은 "어떤 분기마다 평균이 얼마인지를 알면, 분기 확률로 가중해서 전체 평균을 얻는다"는, 매우 자연스러운 사실입니다. 어려운 기댓값을 작은 케이스로 쪼개 푸는 표준 도구예요.

19.5 기댓값의 선형성 Linearity of Expectation

이제 이 챕터에서 가장 강력한 정리, 그리고 거의 마법처럼 작동하는 도구를 소개합니다.

정리 19.5.1 (기댓값의 선형성)

표본공간 \(S\) 위의 어떤 확률변수 \(X, Y\)와 임의의 상수 \(a, b\)에 대해서도 \[\mathrm{E}[aX + bY] = a\, \mathrm{E}[X] + b\, \mathrm{E}[Y].\] 더 일반적으로 \(\mathrm{E}\!\left[\sum_{i=1}^{n} X_i\right] = \sum_{i=1}^{n} \mathrm{E}[X_i]\). 이 등식은 \(X_i\)들이 독립이든 아니든 항상 성립합니다.

증명

두 변수 \(X, Y\)에 대한 식만 보일게요. 기댓값을 결과별 표현으로 쓰면 \[\mathrm{E}[aX + bY] = \sum_{\omega \in S} (aX(\omega) + bY(\omega)) \Pr[\omega] = a \sum_\omega X(\omega) \Pr[\omega] + b \sum_\omega Y(\omega) \Pr[\omega] = a \mathrm{E}[X] + b \mathrm{E}[Y].\] 합이 선형이라는, 거의 자명한 사실에서 곧장 따라옵니다. 독립성은 어디에도 쓰지 않았다는 점에 주목하세요.

증명은 한 줄짜리예요. 그런데 응용은 정말 풍성합니다. 핵심 패턴은 이래요: 복잡해 보이는 확률변수 \(X\)를 단순한 인디케이터들의 합 \(X = I_1 + I_2 + \cdots + I_n\)으로 쓸 수 있으면, 선형성으로 \(\mathrm{E}[X] = \sum_i \mathrm{E}[I_i] = \sum_i \Pr[A_i]\)가 됩니다. 분포 전체를 알 필요 없이 각 사건의 확률만 알면 평균이 나오는 거예요.

예제 19.5.2 (이항 분포의 평균)

\(X \sim \mathrm{Bin}(n, p)\)의 평균을 PMF로부터 직접 계산하면 \(\sum_k k \binom{n}{k} p^k (1-p)^{n-k}\) — 끈질긴 이항계수 조작이 필요해요. 그런데 \(X = X_1 + \cdots + X_n\)으로 쓰고, \(X_i\)는 \(i\)번째 시행의 인디케이터(\(\mathrm{Bern}(p)\))라 하면 \[\mathrm{E}[X] = \sum_{i=1}^{n} \mathrm{E}[X_i] = \sum_{i=1}^{n} p = np.\] 한 줄에 끝납니다. 그리고 \(X_i\)들이 독립인 게 아니라도 이 등식은 통해요.

예제 19.5.3 (랜덤 순열의 고정점)

\(\{1, 2, \ldots, n\}\)의 랜덤 순열 \(\pi\)에서 고정점은 \(\pi(i) = i\)인 \(i\)의 개수입니다. \(F\)를 고정점의 수라 하면 \(\mathrm{E}[F]\)는 얼마일까요?

인디케이터 트릭. \(X_i = 1\) (\(\pi(i) = i\)일 때), \(0\) (아닐 때). 그러면 \(F = \sum_{i=1}^{n} X_i\)이고 \[\mathrm{E}[X_i] = \Pr[\pi(i) = i] = \frac{(n-1)!}{n!} = \frac{1}{n}.\] 따라서 \(\mathrm{E}[F] = \sum_{i=1}^{n} \frac{1}{n} = 1\). \(n\)이 100이든 백만이든, 평균 고정점 수는 항상 1개예요. 멋지죠.

여기서 \(X_i\)들은 절대 독립이 아닙니다(이미 \(n-1\)개가 고정점이면 마지막도 무조건 고정점). 그래도 선형성은 통합니다.

예제 19.5.4 (쿠폰 수집가 문제)

가챠 게임에서 \(n\)종류의 캐릭터를 모두 모으려면 평균 몇 번 뽑아야 할까요? 매번 \(n\)개 중 하나가 균등 확률로 나오고 독립이라 합시다.

\(T\)를 모두 모을 때까지의 총 횟수, \(T_k\)를 정확히 \(k-1\)종을 모은 상태에서 새로운 종을 처음 얻기까지 걸리는 횟수라 합시다. 그러면 \(T = T_1 + T_2 + \cdots + T_n\) 이에요.

\(k-1\)종을 모은 시점에서 새로운 종이 나올 확률은 \(p_k = (n - (k-1))/n = (n-k+1)/n\). 그래서 \(T_k \sim \mathrm{Geo}(p_k)\)이고 \(\mathrm{E}[T_k] = 1/p_k = n/(n-k+1)\). 선형성으로 \[\mathrm{E}[T] = \sum_{k=1}^{n} \frac{n}{n-k+1} = n \sum_{j=1}^{n} \frac{1}{j} = n H_n\] 입니다. 여기서 \(H_n\)은 \(n\)번째 조화수예요. \(H_n \approx \ln n + \gamma\) 이니까 \(\mathrm{E}[T] \approx n \ln n\). \(n=100\)이면 약 \(518\)번, \(n=1000\)이면 약 \(7485\)번 — 가챠가 왜 그렇게 잔인한지 수학적으로 보이는 결과입니다.

노트 (선형성 vs. 곱의 기댓값)

\(\mathrm{E}[X+Y] = \mathrm{E}[X] + \mathrm{E}[Y]\)는 항상 옳지만, \(\mathrm{E}[XY] = \mathrm{E}[X] \mathrm{E}[Y]\)는 일반적으로 거짓입니다. 단, \(X, Y\)가 독립이면 곱도 분리돼요. 분산이 합으로 분해되려면 독립(또는 적어도 무상관)이 필요한데, 평균이 합으로 분해되는 데에는 그게 필요 없다 — 이 비대칭이 선형성의 힘입니다.

19.6 정말 큰 기대 Really Great Expectations

기댓값이 늘 단순한 가중평균처럼 행동하는 건 아니에요. 합이 무한급수가 되거나, 음·양의 값이 섞이거나, 조건부로 다시 쓸 때 미묘한 일들이 벌어집니다. 이 절에서는 그런 두 가지 사례를 다뤄볼게요.

예제 19.6.1 (조건부 기댓값으로 풀기)

다시 기하 분포 \(X \sim \mathrm{Geo}(p)\)의 평균을 보겠습니다. 이번엔 무한급수 대신 조건부 기댓값으로요. 첫 시행이 성공이면 \(X = 1\); 실패면 처음 시행 한 번이 헛수고이고 그 뒤로는 같은 분포가 다시 시작됩니다(메모리리스 성질).

\(A\)를 "첫 시행 성공" 사건이라 하면 \(\Pr[A] = p\), \(\mathrm{E}[X \mid A] = 1\), \(\mathrm{E}[X \mid A^c] = 1 + \mathrm{E}[X]\) 입니다. 전체 기댓값 법칙으로 \[\mathrm{E}[X] = p \cdot 1 + (1-p)(1 + \mathrm{E}[X]).\] 정리하면 \(\mathrm{E}[X] = 1 + (1-p) \mathrm{E}[X]\), 따라서 \(\mathrm{E}[X] = 1/p\). 19.4절에서 미분 트릭으로 얻은 결과와 같지만, 한 줄짜리 자기참조 방정식으로 끝났어요. 무한급수를 다루지 않고도 무한 시행의 평균을 구할 수 있다는 게 조건부 기댓값의 힘입니다.

예제 19.6.2 (성트페테르부르크 역설 — 무한 기댓값)

도박 한 판을 생각해 봅시다. 동전을 앞면이 나올 때까지 던지는데, 처음으로 \(k\)번째 던지기에서 앞면이 나오면 \(2^k\)원을 받습니다. \(X\)를 받는 금액이라 하면 \[\mathrm{E}[X] = \sum_{k=1}^{\infty} 2^k \cdot \Pr[\text{첫 앞면이 } k \text{번째}] = \sum_{k=1}^{\infty} 2^k \cdot \frac{1}{2^k} = \sum_{k=1}^{\infty} 1 = \infty.\] 평균 상금이 무한대! 그러면 이 게임에 참가하기 위해 얼마든 — 백만 원이라도 — 내야 한다는 뜻일까요? 실제로 사람들은 그렇게 행동하지 않습니다. 이게 18세기 베르누이 형제가 제기한 성트페테르부르크 역설이에요. 기댓값이 무한이면 "평균"이라는 직관 자체가 깨질 수 있다는 경고입니다.

노트 (기댓값이 정의되지 않을 수 있다)

이산확률변수의 기댓값 정의 \(\mathrm{E}[X] = \sum_x x \Pr[X=x]\)는 합이 절대수렴할 때만 의미 있어요. 양과 음이 섞여 조건부수렴만 한다면, 합의 순서에 따라 값이 바뀝니다(리만 재배열 정리). 그래서 엄밀히는 \(\mathrm{E}[|X|] = \infty\)인 경우 "기댓값이 존재하지 않는다"고 표현해요. 알고리즘이나 시뮬레이션에서 평균을 다룰 땐 이런 가능성을 잊지 마세요.

그럼에도 불구하고 기댓값과 그 선형성은 조합론, 알고리즘, 그리고 일상의 의사결정에 끊임없이 등장하는 도구입니다. 인디케이터 트릭은 한 번 익숙해지면 거의 모든 "평균 ~ 의 개수" 문제에 통하는 만능 열쇠예요. 다음 챕터에서는 평균만으로는 부족할 때 — 즉, 평균에서 얼마나 벗어나는지를 측정하는 분산과 편차 부등식들 — 을 다루겠습니다.

정리하며

이 챕터에서 챙겨야 할 것: (1) 확률변수는 표본공간에서 \(\mathbb{R}\)로 가는 함수다. (2) 분포는 PMF/CDF로 표현된다. 베르누이·이항·기하·균등을 손에 익혀라. (3) 기댓값은 가중평균이고, 인디케이터의 기댓값은 사건의 확률이다. (4) 기댓값의 선형성은 항상 성립한다 — 독립 없어도. 이게 거의 마법이다. (5) 무한 기댓값처럼 미묘한 경우가 존재하니, 합의 수렴은 늘 의식하라.

PART IV — 확률

20 평균에서의 이탈 Deviation from the Mean

기댓값은 확률변수의 "중앙"을 알려주는 한 점입니다. 하지만 실제 값이 그 중앙에서 얼마나 벗어날 수 있는지는 또 다른 이야기예요. 같은 평균을 가진 두 확률변수라도 어떤 것은 거의 평균 근처에 머물고, 어떤 것은 사방팔방으로 흩어집니다. 이번 챕터에서는 "기댓값은 중앙을 알려주고, 분산은 흔들림을 알려준다"는 구호를 깃발 삼아, 확률변수가 평균에서 멀어질 확률을 부등식으로 통제하는 방법을 배웁니다. 그리고 이 도구들을 모아 큰 수의 법칙(약한 형태)까지 도달해 봅니다.

20.1 마르코프 부등식 Markov's Theorem

여러분이 어느 빵집의 일일 매출 데이터를 받았다고 합시다. 일일 매출의 평균이 100만 원이라는 사실 하나만 알 때, "어느 날의 매출이 1000만 원을 넘을 확률"에 대해 무슨 말을 할 수 있을까요? 매출의 분포 모양을 모르므로 정확한 값은 못 구합니다. 그래도 "그런 일은 자주 못 일어난다"는 직관은 분명히 있어요. 평균이 100만 원인데 매일 1000만 원씩 찍히면 평균이 그렇게 작을 리가 없잖아요. 마르코프 부등식은 바로 이 직관을 식 한 줄로 굳힌 것입니다.

정리 20.1.1 (마르코프 부등식, Markov's Inequality)

\( X \)가 음이 아닌(non-negative) 확률변수이고 \( a > 0 \)이면 \[ \Pr[X \ge a] \le \frac{\mathrm{E}[X]}{a}. \]

증명

\( X \ge 0 \)이라는 가정이 핵심입니다. 다음 두 사건을 비교해 봅시다. 사건 \( A = \{X \ge a\} \)에서는 \( X \ge a \)이고, 그 보집합에서는 \( X \ge 0 \)이에요. 따라서

\[ \mathrm{E}[X] = \sum_{x} x \cdot \Pr[X = x] \;\ge\; \sum_{x \ge a} x \cdot \Pr[X = x] \;\ge\; \sum_{x \ge a} a \cdot \Pr[X = x] = a \cdot \Pr[X \ge a]. \]

양변을 \( a \)로 나누면 부등식이 나옵니다. (연속형이면 합 대신 적분이지만 논리는 같아요.)

예제 20.1.2 (시험 점수)

어떤 시험의 평균 점수가 75점이라고 합시다. 점수는 0점 이상 100점 이하예요. "90점 이상 받을 학생의 비율"의 상한을 구해 봅시다. 마르코프 부등식을 그대로 쓰면 \( \Pr[X \ge 90] \le 75/90 \approx 0.833 \). 즉 90점 이상은 많아야 약 83%라는 뻔한 결과예요. 별로 도움이 안 되는 것 같죠? 맞아요, 마르코프는 정보가 평균밖에 없을 때 짜낼 수 있는 가장 약한 한계입니다.

하지만 같은 도구라도 변수를 바꿔 끼우면 더 날카로워집니다. 예컨대 "0점부터 측정된 평균" 대신 "75점에서 떨어진 양"을 보면, \( Y = 100 - X \)의 평균은 25이고 \( Y \ge 100 - 90 = 10 \)이라는 사건은 원래 사건 \( X \le 90 \)과 같습니다. 마르코프를 \( Y \)에 적용하면 \( \Pr[X \le 90] = \Pr[Y \ge 10] \le 25/10 \), 이건 1을 넘어 무용지물. 즉 한계는 변수의 모양에 따라 유용할 때도, 그렇지 않을 때도 있다는 점을 기억해 두세요.

노트 (마르코프의 한계)

마르코프 부등식이 평범해 보이는 이유는, 분포의 모양에 대한 정보가 "평균이 얼마"라는 한 줄밖에 없기 때문입니다. 분산이나 대칭성 같은 추가 정보를 쓰면 훨씬 좁은 경계를 얻을 수 있어요. 다음 절의 체비셰프가 그 첫걸음입니다. 또 마르코프의 등호는 "값이 0 또는 \( a \) 단 두 개"인 분포에서 달성된다는 점도 꼭 짚어 둡시다. 즉 한계는 일반적으로는 느슨하지만, 어떤 분포에서는 정확합니다.

20.2 체비셰프 부등식 Chebyshev's Theorem

마르코프는 평균만 알 때 쓰는 도구였습니다. 만약 평균뿐 아니라 "값이 평균에서 얼마나 흩어져 있는지"까지 안다면 어떨까요? 흩어짐을 잰 양이 분산입니다. 분산이 작으면 변수는 평균 근처에 빽빽하게 몰려 있을 거고, 분산이 크면 사방으로 퍼져 있겠죠. 체비셰프 부등식은 이 직관을 살짝 더 정량적으로 다듬은 결과입니다.

정의 20.2.1 (분산과 표준편차)

확률변수 \( X \)의 평균을 \( \mu = \mathrm{E}[X] \)라 할 때, 분산은 \[ \mathrm{Var}(X) = \mathrm{E}\!\left[(X-\mu)^2\right]. \] 표준편차는 \( \sigma = \sqrt{\mathrm{Var}(X)} \)로 정의합니다. 분산은 "평균에서의 제곱 거리"의 평균이라고 외워 두면 좋아요.

정리 20.2.2 (체비셰프 부등식)

\( X \)의 평균이 \( \mu \), 표준편차가 \( \sigma > 0 \)일 때 임의의 \( k > 0 \)에 대해 \[ \Pr\!\left[|X - \mu| \ge k\sigma\right] \le \frac{1}{k^2}. \] 더 일반적으로, 임의의 \( a > 0 \)에 대해 \[ \Pr\!\left[|X - \mu| \ge a\right] \le \frac{\mathrm{Var}(X)}{a^2}. \]

증명

핵심 트릭은 "양수가 아닌 양을 양수로 만드는 제곱"입니다. \( Y = (X - \mu)^2 \)으로 두면 \( Y \ge 0 \). 그리고 \( |X - \mu| \ge a \)와 \( Y \ge a^2 \)은 같은 사건이에요. 이제 비음 변수 \( Y \)에 마르코프를 적용하면

\[ \Pr[Y \ge a^2] \le \frac{\mathrm{E}[Y]}{a^2} = \frac{\mathrm{Var}(X)}{a^2}. \]

여기에 \( a = k\sigma \)를 넣으면 \( \mathrm{Var}(X)/a^2 = \sigma^2/(k\sigma)^2 = 1/k^2 \).

예제 20.2.3 (3시그마 규칙의 약한 형태)

어떤 측정값의 평균이 \( \mu \), 표준편차가 \( \sigma \)일 때 "평균에서 3시그마 이상 떨어질 확률"은? 체비셰프에 \( k = 3 \)을 넣으면 \( \Pr[|X - \mu| \ge 3\sigma] \le 1/9 \approx 0.111 \). 정규분포에서는 이게 약 0.0027로 훨씬 작지만, 분포 모양을 모를 땐 1/9이 우리가 줄 수 있는 보장이에요. 즉 체비셰프는 "어떤 분포든" 통하는 보편적 안전선입니다.

예제 20.2.4 (작은 분산이 주는 힘)

한 시스템의 응답시간 \( T \)의 평균이 100ms, 분산이 25(즉 \( \sigma = 5 \)ms)라 합시다. "응답시간이 120ms를 넘을 확률"에 대해 체비셰프는 \( \Pr[|T - 100| \ge 20] \le 25/400 = 1/16 \). 흥미로운 건 분산이 작아질수록 이 한계가 빠르게 좋아진다는 점입니다. 분산이 1로 줄면 같은 사건의 확률은 \( 1/400 \) 이하로 떨어져요. 흩어짐이 작을수록 평균에서 멀어지기 어렵다는 직관과 정확히 맞습니다.

노트 (마르코프 → 체비셰프 → 그다음)

증명을 다시 보세요. 체비셰프는 결국 \( (X-\mu)^2 \)에 마르코프를 쓴 것입니다. 같은 트릭을 \( e^{tX} \) 같은 지수함수에 적용하면 더 강력한 체르노프(Chernoff) 한계가 나옵니다. 챕터의 한참 뒤에서 다루지만, 모든 집중부등식의 뿌리는 한 그루인 셈이에요.

20.3 분산의 성질 Properties of Variance

분산을 "정의대로" 매번 \( \mathrm{E}[(X-\mu)^2] \)로 계산하는 건 불편합니다. 두 가지 도구를 갖춰 두면 한결 빨라져요. 하나는 분산을 다른 형태로 풀어 쓰는 항등식, 또 하나는 합의 분산을 합으로 나누는 법칙입니다.

정리 20.3.1 (분산의 계산식)

\[ \mathrm{Var}(X) = \mathrm{E}[X^2] - (\mathrm{E}[X])^2. \]

증명

\( \mu = \mathrm{E}[X] \)는 상수이므로 기댓값의 선형성을 그대로 풀어 쓰면

\[ \mathrm{E}[(X-\mu)^2] = \mathrm{E}[X^2 - 2\mu X + \mu^2] = \mathrm{E}[X^2] - 2\mu\,\mathrm{E}[X] + \mu^2 = \mathrm{E}[X^2] - \mu^2. \]

예제 20.3.2 (공정한 6면 주사위)

주사위의 눈을 \( X \)라 하면 \( \mathrm{E}[X] = 3.5 \). 그리고 \[ \mathrm{E}[X^2] = \frac{1^2 + 2^2 + \cdots + 6^2}{6} = \frac{91}{6} \approx 15.17. \] 따라서 \( \mathrm{Var}(X) = 91/6 - 49/4 = 35/12 \approx 2.92 \), 표준편차는 약 1.71. 평균 3.5에서 약 1.71 떨어진 자리에 "전형적인 흔들림"이 있다는 뜻이에요.

정리 20.3.3 (스케일·이동, 합의 분산)

임의의 상수 \( a, b \)와 확률변수 \( X, Y \)에 대해 \[ \mathrm{Var}(aX + b) = a^2 \mathrm{Var}(X). \] 또한 \( X \)와 \( Y \)가 독립이면 \[ \mathrm{Var}(X + Y) = \mathrm{Var}(X) + \mathrm{Var}(Y). \] 더 일반적으로, \( X_1, \ldots, X_n \)이 쌍별로 독립이면 \[ \mathrm{Var}\!\left(\sum_{i=1}^n X_i\right) = \sum_{i=1}^n \mathrm{Var}(X_i). \]

증명 스케치

이동 \( +b \)는 평균을 같이 옮기므로 편차 \( X - \mu \)에는 영향을 주지 않습니다. 그래서 분산은 변하지 않아요. 스케일 \( a \)를 곱하면 편차도 \( a \)배가 되고 제곱하면 \( a^2 \)배. 그래서 \( a^2 \mathrm{Var}(X) \).

독립합의 분산은 다음과 같이 풉니다. \( \mu_X, \mu_Y \)를 평균이라 하면 \[ \mathrm{Var}(X+Y) = \mathrm{E}\!\left[((X-\mu_X) + (Y-\mu_Y))^2\right] = \mathrm{Var}(X) + \mathrm{Var}(Y) + 2\,\mathrm{Cov}(X, Y). \] 여기서 공분산 \( \mathrm{Cov}(X,Y) = \mathrm{E}[(X-\mu_X)(Y-\mu_Y)] \)이고, 독립이면 \( \mathrm{E}[(X-\mu_X)(Y-\mu_Y)] = \mathrm{E}[X-\mu_X]\,\mathrm{E}[Y-\mu_Y] = 0 \). 따라서 교차항이 사라집니다.

노트 (독립이 깨지면?)

합의 분산이 분산의 합과 같으려면 "독립" 또는 적어도 "쌍별 비상관(공분산이 0)"이 필요합니다. 두 변수가 양의 상관이면 \( \mathrm{Var}(X+Y) \)가 더 커지고, 음의 상관이면 더 작아져요. 위험을 분산할 때 "음의 상관 자산을 섞는" 분산투자의 직관이 여기서 나옵니다.

예제 20.3.4 (\( n \)번 주사위의 합)

주사위를 \( n \)번 굴려 그 합을 \( S_n = X_1 + \cdots + X_n \)이라 하면, 각 \( X_i \)의 분산이 \( 35/12 \)이고 모두 독립이므로 \( \mathrm{Var}(S_n) = 35n/12 \). 표준편차는 \( \sqrt{35n/12} \approx 1.71\sqrt{n} \). 합의 평균은 \( 3.5 n \)으로 \( n \)에 비례해 커지지만, 표준편차는 \( \sqrt{n} \)에만 비례한다는 점이 핵심이에요. "상대적인 흔들림"이 \( n \)이 커질수록 줄어드는 것, 이게 곧 큰 수의 법칙으로 이어집니다.

20.4 무작위 표본 추정 Estimation by Random Sampling

실제 응용에서 우리는 모집단 전체를 관찰하지 못합니다. 대신 일부를 무작위로 골라 평균을 재고, 그 표본 평균이 모평균에 얼마나 가까운지 추정해야 해요. 여론조사, A/B 테스트, 몬테카를로 시뮬레이션 모두 똑같은 구조입니다. 이 절에서는 체비셰프를 이용해 "표본을 몇 개 뽑아야 충분한가"를 답하는 가장 단순한 방법을 살펴봅니다.

모집단에서 같은 분포로 독립적으로 뽑은 표본을 \( X_1, X_2, \ldots, X_n \)이라 합시다. 모평균은 \( \mu \), 모분산은 \( \sigma^2 \). 표본 평균은 \[ \bar{X}_n = \frac{1}{n}\sum_{i=1}^n X_i. \] 이 \( \bar{X}_n \) 자체가 확률변수예요. 우리는 이 새로운 변수의 평균과 분산을 이미 가진 도구로 계산할 수 있습니다.

정리 20.4.1 (표본 평균의 평균과 분산)

\[ \mathrm{E}[\bar{X}_n] = \mu, \qquad \mathrm{Var}(\bar{X}_n) = \frac{\sigma^2}{n}. \]

증명 스케치

기댓값의 선형성으로 \( \mathrm{E}[\bar{X}_n] = (1/n) \sum \mathrm{E}[X_i] = \mu \). 분산은 스케일과 독립합 법칙을 함께 써서

\[ \mathrm{Var}(\bar{X}_n) = \mathrm{Var}\!\left(\tfrac{1}{n}\sum X_i\right) = \tfrac{1}{n^2} \sum \mathrm{Var}(X_i) = \tfrac{n\sigma^2}{n^2} = \tfrac{\sigma^2}{n}. \]

중요한 포인트는 표본 평균의 표준편차가 \( \sigma/\sqrt{n} \)으로 줄어든다는 것입니다. 표본을 100배로 늘려도 정확도는 10배밖에 좋아지지 않아요. 이 "1/제곱근" 비율이 통계학 비용 구조의 본질입니다.

정리 20.4.2 (체비셰프 기반 표본 크기 공식)

오차 허용범위 \( \varepsilon > 0 \)과 신뢰도 \( 1 - \delta \)에 대해, 표본 크기 \( n \)이 \[ n \ge \frac{\sigma^2}{\varepsilon^2 \delta} \] 을 만족하면 \( \Pr[|\bar{X}_n - \mu| \ge \varepsilon] \le \delta \).

증명

표본 평균 \( \bar{X}_n \)에 체비셰프(분산 형태)를 적용하면 \[ \Pr[|\bar{X}_n - \mu| \ge \varepsilon] \le \frac{\mathrm{Var}(\bar{X}_n)}{\varepsilon^2} = \frac{\sigma^2}{n \varepsilon^2}. \] 이걸 \( \delta \)보다 작거나 같게 만들면 \( n \ge \sigma^2 / (\varepsilon^2 \delta) \).

예제 20.4.3 (여론조사)

어떤 후보의 지지율 \( p \)를 추정한다고 합시다. 한 사람의 응답 \( X_i \)는 0 또는 1이고 \( \mathrm{E}[X_i] = p, \mathrm{Var}(X_i) = p(1-p) \le 1/4 \). 오차 \( \pm 3\%p\) 안쪽에 95% 확률로 들어오게 하려면 \( \varepsilon = 0.03, \delta = 0.05 \)로 두고 \[ n \ge \frac{1/4}{(0.03)^2 \cdot 0.05} = \frac{0.25}{0.0000045} \approx 55{,}556. \] 체비셰프는 분포 모양에 무지한 보편 보장이라 큰 표본을 요구합니다. 실제 여론조사가 1000~2000명으로 끝나는 건 정규근사(중심극한정리)를 가정하기 때문이에요. 그래도 "모르는 분포에서 안전하게" 가려면 체비셰프가 합리적 출발선입니다.

노트 (신뢰구간의 해석)

"95% 신뢰구간"이라는 말은 미묘합니다. 한 번 계산한 구간 \([\bar{X}_n - \varepsilon, \bar{X}_n + \varepsilon]\)이 모평균 \( \mu \)를 95% 확률로 포함한다는 뜻이 아니에요. 같은 절차를 여러 번 반복했을 때, 그렇게 만들어진 구간들 중 약 95%가 \( \mu \)를 덮는다는 뜻입니다. \( \mu \)는 (빈도주의 시각에서는) 고정된 미지의 수이지 확률변수가 아니에요.

20.5 확률변수의 합과 큰 수의 법칙 Sums of Random Variables

지난 절들에서 우리는 두 가지 사실을 모았습니다. 첫째, 독립합의 분산은 분산의 합이다. 둘째, 표본 평균의 분산은 \( \sigma^2/n \)이다. 이 두 도구만 가지고도 확률론에서 가장 유명한 정리 중 하나인 "큰 수의 법칙"의 약한 형태를 단단하게 증명할 수 있어요. 이름이 거창해서 어려워 보이지만, 본질은 한 줄입니다. "표본을 충분히 모으면 표본 평균은 모평균에 거의 확실하게 가깝다."

정리 20.5.1 (약한 큰 수의 법칙, Weak Law of Large Numbers)

\( X_1, X_2, \ldots \)이 평균 \( \mu \), 분산 \( \sigma^2 < \infty \)인 동분포 독립 확률변수열이고 \( \bar{X}_n = \frac{1}{n}\sum_{i=1}^n X_i \)이면, 임의의 \( \varepsilon > 0 \)에 대해 \[ \lim_{n \to \infty} \Pr\!\left[|\bar{X}_n - \mu| \ge \varepsilon\right] = 0. \]

증명 (체비셰프 한 줄)

표본 평균에 체비셰프를 적용하면 이미 봤듯이 \[ \Pr\!\left[|\bar{X}_n - \mu| \ge \varepsilon\right] \le \frac{\sigma^2}{n \varepsilon^2}. \] \( \varepsilon \)을 고정한 채 \( n \to \infty \)로 보내면 우변이 0으로 수렴하므로 좌변도 0으로 수렴합니다.

증명 한 줄이 너무 짧아 보일지도 모르지만, 그 한 줄을 가능하게 한 인프라는 결코 짧지 않았어요. 기댓값의 선형성, 독립합의 분산, 분산의 계산식, 마르코프, 체비셰프, 표본 평균의 분산 공식 — 이 모든 부품이 있어야 마지막 한 줄이 의미를 가집니다. 책의 한 챕터가 어떻게 모여 큰 정리를 받쳐 주는지 보여주는 좋은 예시예요.

예제 20.5.2 (몬테카를로 적분)

함수 \( f: [0,1] \to \mathbb{R} \)의 적분 \( I = \int_0^1 f(x)\,dx \)를 컴퓨터로 추정하고 싶다고 합시다. \( U_1, \ldots, U_n \)을 \([0,1]\)에서 독립 균등 분포로 뽑고 \[ \hat{I}_n = \frac{1}{n} \sum_{i=1}^n f(U_i) \] 을 추정값으로 씁니다. \( \mathrm{E}[f(U_i)] = I \)이므로 약한 큰 수의 법칙에 의해 \( \hat{I}_n \)은 \( n \to \infty \)일 때 확률적으로 \( I \)에 수렴합니다. 추정 오차의 표준편차는 \( \mathrm{Var}(f(U_1))/\sqrt{n} \) 정도로 줄어들고요. 차원이 높아져도 \( 1/\sqrt{n} \)이라는 비율이 그대로 유지된다는 점이 몬테카를로의 강력함입니다.

예제 20.5.3 (도박꾼의 환상)

공정한 동전 던지기에서 앞면이 나오면 +1, 뒷면이면 -1이라고 합시다. 평균은 0. \( S_n = X_1 + \cdots + X_n \)은 시행 \( n \)회 후 잔고예요. 사람들은 종종 "큰 수의 법칙이 있으니 \( S_n \)도 0에 가까워질 것"이라 오해합니다. 그러나 큰 수의 법칙이 말하는 건 \( S_n/n \)이 0에 가까워진다는 것이지, \( S_n \) 자체는 평균적으로 \( \sqrt{n} \)만큼 흔들립니다. 표본 평균은 모평균에 가까워지지만, 합 자체는 점점 더 큰 폭으로 출렁여요. "공정한 도박을 오래 하면 본전을 회복한다"는 건 신화입니다.

노트 (약함 vs 강함, 그리고 그다음)

여기서 증명한 "약한" 큰 수의 법칙은 확률적 수렴(probability convergence)이라고 부르는 약한 형태의 수렴입니다. "강한" 큰 수의 법칙은 거의 확실한 수렴(almost sure convergence)을 보장하는데, 그건 더 정교한 도구가 필요해 보통 측도론을 다루는 강의에서 다뤄요. 또 한 단계 더 나아가면 \( \sqrt{n}(\bar{X}_n - \mu) \)의 분포가 정규분포로 가까워진다는 중심극한정리(CLT)가 기다리고 있습니다. 그러나 이번 챕터의 무대는 여기서 막을 내립니다. 부등식 두 개와 분산 한 줌으로도 큰 수의 법칙에 도달할 수 있다는 사실, 그게 오늘의 수확이에요.

정리 한 줄 요약

마르코프는 평균만으로 꼬리 확률을 누르고, 체비셰프는 \( (X-\mu)^2 \)에 마르코프를 다시 써서 분산으로 더 좁게 누른다. 분산의 선형성(독립일 때)은 합과 평균의 분산을 폭발하지 않게 통제해 주고, 그 통제를 체비셰프와 합치면 표본 평균은 \( n \)이 커질수록 모평균에 수렴한다. 이게 약한 큰 수의 법칙이다.

PART IV — 확률

21 임의 보행 Random Walks

동전을 던지며 이리저리 걷는 사람을 상상해 보세요. 앞면이 나오면 한 칸 오른쪽, 뒷면이 나오면 한 칸 왼쪽. 단순해 보이지만 이 작은 그림은 자연 현상부터 금융 시장, 구글 검색 엔진의 심장부까지 두루 설명하는 강력한 도구예요. 이번 챕터에서는 1차원 임의 보행에서 출발해, 그래프 위 임의 보행, 그리고 PageRank의 직관까지 한 번에 따라가 봅니다.

21.1 도박꾼의 파산 Gambler's Ruin

장면을 하나 그려봅시다. 카지노에 들어선 도박꾼이 처음에 \( n \)달러를 가지고 있어요. 매 라운드마다 동전을 던져 앞면이면 1달러를 따고, 뒷면이면 1달러를 잃습니다. 도박꾼은 가진 돈이 \( T \)달러가 되면 의기양양하게 자리를 뜨겠다고 다짐했지만, 반대로 0달러가 되면 어쩔 수 없이 자리를 떠야 해요. 자, 그가 목표 \( T \)달러에 도달할 확률은 얼마일까요? 그리고 게임이 끝날 때까지 평균 몇 라운드를 버틸 수 있을까요?

이 문제를 도박꾼의 파산이라고 부르는데요, 18세기부터 사람들이 골머리를 앓아 온 고전 문제입니다. 표면적으로는 도박 이야기지만, 사실은 1차원 격자 위 임의 보행의 가장 깔끔한 형태예요. 정수 직선 위 \( n \)에서 출발해 매 단계마다 \( +1 \) 또는 \( -1 \)을 더하며 움직이고, 0이나 \( T \)에 닿으면 멈추는 거죠.

정의 21.1.1 (도박꾼의 파산 모형)

고정된 정수 \( 0 \le n \le T \)와 \( 0 < p < 1 \)에 대해, 다음과 같은 과정 \( X_0, X_1, X_2, \dots \)을 생각합니다. \( X_0 = n \)이고, \( X_t \in \{0, T\} \)이면 과정은 멈춥니다. 그렇지 않으면 독립적으로 확률 \( p \)로 \( X_{t+1} = X_t + 1 \), 확률 \( q = 1-p \)로 \( X_{t+1} = X_t - 1 \) 입니다. 우리가 알고 싶은 것은 두 가지: 멈출 때 \( X = T \)일 확률 \( w_n \)과 멈출 때까지의 기대 단계 수 \( e_n \)입니다.

직관적으로 \( p \)가 \( 1/2 \)에 가까우면 양쪽으로 비슷하게 흔들리니까 도박꾼이 살아날 가능성도 한가운데서 \( n/T \)쯤 될 것 같죠. 반대로 \( p < 1/2 \)인 약간 불공정한 게임이라면 카지노가 점점 도박꾼의 돈을 빨아들일 거고, \( p > 1/2 \)이면 도박꾼이 유리할 거예요. 이 직관을 정확한 식으로 만들어 봅시다.

점화식으로 파산 확률 풀기

핵심 아이디어는 한 걸음 조건부 분석(one-step conditioning)이에요. 도박꾼이 현재 \( n \)달러를 가지고 있을 때 목표를 달성할 확률을 \( w_n \)이라고 합시다. 첫 번째 동전을 던진 직후를 보면, 이전과 같은 모양의 게임이 약간 다른 자본금에서 시작됩니다. 그러니

\[ w_n = p \cdot w_{n+1} + q \cdot w_{n-1}, \qquad 1 \le n \le T-1 \]

이 됩니다. 경계조건은 \( w_0 = 0 \) (이미 파산), \( w_T = 1 \) (이미 우승)이고요. 이건 우리가 이전 챕터에서 봤던 선형 점화식이에요. 일반 해를 찾아봅시다.

정리 21.1.2 (도박꾼의 파산 확률)

\( p \ne 1/2 \)이고 \( r = q/p \)라고 두면, \[ w_n = \frac{1 - r^n}{1 - r^T}. \] \( p = 1/2 \)인 공정한 게임의 경우에는 \[ w_n = \frac{n}{T} \] 입니다.

증명 스케치

점화식 \( p \, w_{n+1} - w_n + q \, w_{n-1} = 0 \)의 특성방정식은 \( p x^2 - x + q = 0 \). 인수분해하면 \( (px - q)(x - 1) = 0 \)이라 근은 \( x = 1 \)과 \( x = q/p = r \).

\( r \ne 1 \) (즉 \( p \ne 1/2 \))일 때 일반해는 \( w_n = A + B r^n \). 경계조건 \( w_0 = 0 \)에서 \( A + B = 0 \), \( w_T = 1 \)에서 \( A + B r^T = 1 \). 두 식을 풀면 \( B = -A \)이고 \( A(1 - r^T) = -1 \)이므로 결국 \( w_n = (1 - r^n)/(1 - r^T) \).

\( p = 1/2 \)일 때는 두 근이 겹치므로 일반해의 형태가 \( w_n = A + B n \)이고, 같은 경계조건에서 \( w_n = n/T \)가 곧장 나옵니다.

예제 21.1.3 (공정한 게임)

도박꾼이 100달러를 들고 들어가서 목표가 200달러, 동전이 공정하다(\( p = 1/2 \))고 합시다. 그러면 목표에 도달할 확률은 정확히 \( 100/200 = 1/2 \). 자, 그런데 만약 100달러로 백만 달러를 노린다면? \( w_{100} = 100/1{,}000{,}000 = 0.0001 \). 즉 0.01%예요. 공정한 게임이라도 자본 차이가 크면 작은 쪽이 거의 확실히 망합니다.

예제 21.1.4 (살짝 불리한 게임)

룰렛에서 빨강에 거는 시뮬레이션을 해 봅시다. 미국식 룰렛은 38칸 중 18칸이 빨강이라 \( p = 18/38 \approx 0.474 \), \( q = 20/38 \approx 0.526 \), \( r = q/p = 10/9 \). 도박꾼이 100달러로 200달러를 노리면 \[ w_{100} = \frac{1 - (10/9)^{100}}{1 - (10/9)^{200}} \approx \frac{-3 \times 10^4}{-9 \times 10^8} \approx 3 \times 10^{-5}. \] 고작 100달러를 두 배로 만들 확률이 0.003%! 작은 편향(\( p \)가 \( 1/2 \)에서 0.026 떨어짐)이 100라운드 동안 누적되면 거의 확정적인 패배가 됩니다. 카지노가 작은 마진만으로도 장기적으로 이기는 이유예요.

기대 시간: 게임은 얼마나 길까?

파산 확률을 알았으니 이제 게임의 길이도 따져봅시다. 시작 자본이 \( n \)일 때 게임이 끝날 때까지 걸리는 기대 라운드 수를 \( e_n \)이라고 둘게요. 같은 한 걸음 분석으로

\[ e_n = 1 + p \, e_{n+1} + q \, e_{n-1}, \qquad 1 \le n \le T-1, \]

\( e_0 = e_T = 0 \). 첫 번째 동전 한 번을 항상 더해주는 게 핵심이에요. 이 점화식의 동차부분은 위와 같고, 비동차항이 상수 \( -1 \)이라 특수해를 따로 잡아야 해요.

정리 21.1.5 (도박꾼의 파산 기대 시간)

\( p = 1/2 \)일 때 \( e_n = n(T-n) \). 즉 양 끝에서 멀수록 기대 시간이 커지고, 한가운데 \( n = T/2 \)에서 최대 \( T^2/4 \)가 됩니다.

\( p \ne 1/2 \)일 때는 \[ e_n = \frac{1}{q-p} \left( n - T \cdot \frac{1 - r^n}{1 - r^T} \right). \]

특히 공정한 게임에서 \( T = 100 \), \( n = 50 \)이면 평균 \( 50 \cdot 50 = 2500 \)라운드. \( T = 1000 \), \( n = 500 \)이면 평균 25만 라운드! 한가운데서 시작한 임의 보행이 한쪽 끝에 닿기까지 평균적으로 \( T^2 \) 정도 시간이 걸린다는 건, 임의 보행이 느리다는 의미예요. 거리에 비해 제곱만큼 시간이 든다는 \( \sqrt{t} \)–법칙은 확산(diffusion)의 본질이고, 브라운 운동이나 열 방정식과 같은 뿌리에서 자라난 결과입니다.

노트: 한국어 학생이 헷갈리기 쉬운 점

"공정한 게임에서 무한히 길게 두면 결국 본전을 찾지 않을까?"라는 질문을 자주 받아요. 무한 직선이라면 그렇지만(언젠가 0에 돌아오긴 합니다), 경계가 있는 도박꾼의 파산에서는 그 전에 0이나 \( T \)에 부딪혀 게임이 끝나요. 멈추는 시점이 유한하다는 게 결정적입니다. 그리고 무한 직선에서도 2차원까지는 원점에 다시 돌아올 확률이 1이지만, 3차원 이상에서는 영영 못 돌아올 수 있어요. 폴리아의 정리라고 부르는 신기한 사실이죠.

도박꾼의 파산은 단지 도박 이야기가 아니에요. 같은 점화식이 화학에서 분자가 막 사이를 통과할 확률, 신경과학에서 뉴런의 발화 임계값 도달 확률, 알고리즘에서 SAT 해법의 임의 재시작 분석에 등장합니다. "확률적인 한 걸음을 반복했을 때 어디서 멈추나"라는 질문은 정말 어디에나 있어요.

21.2 그래프 위 임의 보행 Random Walks on Graphs

직선 위에서 좌우로만 움직이는 보행은 너무 평면적이에요. 실제로 우리가 흥미로운 구조 — 소셜 네트워크, 도시 도로망, 웹 페이지의 하이퍼링크 — 는 그래프 모양이거든요. 그래서 임의 보행을 그래프로 일반화해 봅시다.

정의 21.2.1 (그래프 위 단순 임의 보행)

유한 그래프 \( G = (V, E) \) (방향 또는 무방향)와 시작 정점 \( v_0 \in V \)이 주어졌을 때, \( t = 0, 1, 2, \dots \)에 대해 다음을 반복합니다. 현재 위치 \( v_t \)에서 이웃들의 집합 \( N(v_t) \) 중 하나를 균등하게 무작위로 골라 \( v_{t+1} \)로 옮겨갑니다. 이렇게 만들어진 정점 수열 \( v_0, v_1, v_2, \dots \)이 그래프 \( G \) 위 단순 임의 보행이에요.

이 과정은 사실 마르코프 연쇄(Markov chain)의 한 종류예요. 다음 위치 \( v_{t+1} \)이 과거 전체가 아니라 오직 현재 \( v_t \)에만 의존하니까요. 전이 확률 행렬 \( P \)는 \( P_{uv} = 1/\deg(u) \)이면 \( v \in N(u) \), 아니면 0입니다.

예제 21.2.2 (정사각형 위의 보행)

네 정점 \( a, b, c, d \)를 사이클로 연결한 \( C_4 \)를 생각해 봅시다 (\( a-b-c-d-a \)). 매 단계마다 양쪽 이웃 중 하나를 동전 던져 고르니, 사실은 4개 정점 위 1차원 임의 보행과 같죠. 시간이 흐르면 어느 정점에 머물 확률이 모두 \( 1/4 \)로 평형을 이룹니다. 대칭이라 결과가 깔끔해요.

예제 21.2.3 (별 그래프와 편향)

중심 정점 \( c \) 하나에 잎 정점 \( \ell_1, \ell_2, \dots, \ell_k \)가 매달린 별 그래프를 생각해 봅시다. 잎에서 출발하면 다음 단계엔 무조건 \( c \)로 옵니다 (이웃이 \( c \) 하나). 그런데 \( c \)에 오면 다음 단계엔 \( k \)개 잎 중 하나로 균등히 갈라지죠. 직관적으로 보행자는 \( c \)와 잎들 사이를 핑퐁처럼 오갈 거예요. 평형 분포에서 \( c \)에 머물 확률은 \( 1/2 \), 각 잎에 머물 확률은 \( 1/(2k) \). 차수가 큰 정점이 평형에서 더 무겁다는 법칙의 작은 예입니다.

평형 분포: 어디에 가장 오래 머무는가

충분히 오랫동안 임의 보행을 돌리면, 시작 위치는 잊혀지고 어떤 안정된 분포 \( \pi \)로 수렴해요. 무방향 연결 그래프에서 비주기적이면(예컨대 자기 자신으로 가는 변이 하나라도 있거나 홀수 사이클이 있으면) 이 평형 분포는 차수에 비례합니다.

정리 21.2.4 (무방향 그래프 평형 분포)

\( G = (V, E) \)이 연결된 비주기 무방향 그래프이면, 단순 임의 보행은 유일한 평형 분포 \( \pi \)로 수렴하고, 각 정점 \( v \)에 대해 \[ \pi(v) = \frac{\deg(v)}{2|E|} \] 입니다. (\( 2|E| = \sum_v \deg(v) \) 인 점에 유의.)

증명 스케치

평형 조건 \( \pi P = \pi \)를 검증하면 충분해요. 즉 \( \sum_u \pi(u) P_{uv} = \pi(v) \). 무방향 그래프의 인접관계는 대칭이라 \( P_{uv} = 1/\deg(u) \)는 \( u \sim v \)일 때만 \( 1/\deg(u) \). 따라서 \[ \sum_u \pi(u) P_{uv} = \sum_{u \sim v} \frac{\deg(u)}{2|E|} \cdot \frac{1}{\deg(u)} = \frac{\deg(v)}{2|E|} = \pi(v). \] 유일성과 수렴은 비주기성과 연결성에서 페론-프로베니우스 정리로 따라옵니다.

이 결과가 의미하는 바는 단순해요. 이웃이 많은 정점일수록 보행자가 그곳에서 더 많은 시간을 보낸다. 차수가 평형 확률을 결정하고요. 그래프에서 "중요한 정점"을 이웃 수로 정의해도 된다는 첫 신호입니다. 하지만 웹 같은 방향 그래프에서는 이 깔끔한 차수 비례 공식이 그대로 통하지 않아요. 그래서 등장한 게 PageRank입니다.

PageRank: 임의 보행으로 검색을 풀다

1998년 스탠퍼드 박사과정생 두 명, 래리 페이지와 세르게이 브린이 풀고 싶었던 문제는 이거였어요. "웹 페이지가 수십억 개 있다. 검색어가 들어왔을 때 어떤 페이지를 가장 위에 띄울 것인가?" 단순히 "검색어가 등장한 횟수"로 정렬하면 키워드 스팸이 판칠 거고요. 그들의 통찰은 이거였죠. 웹은 거대한 방향 그래프다. 페이지가 페이지를 링크한다는 건 일종의 추천이다. 추천을 많이 받는 페이지가 중요하다. 그런데 추천하는 페이지 자체가 중요할 때 그 추천이 더 무겁다.

이 재귀적 정의를 어떻게 풀까요? 답은 우아하게도 임의 보행이에요. 어떤 가상의 서퍼가 임의의 페이지에서 출발해, 매 단계마다 현재 페이지의 외부 링크 중 하나를 균등하게 골라 클릭한다고 합시다. 이 서퍼가 충분히 오래 떠돌면 어떤 페이지에 머물 확률 분포가 평형을 이루는데, 그 평형 확률이 곧 그 페이지의 중요도입니다. 즉 임의 보행이 오래 머무는 페이지가 중요한 페이지예요.

정의 21.2.5 (PageRank, 단순 버전)

웹 그래프 \( G = (V, E) \)의 각 페이지 \( v \)의 PageRank \( \pi(v) \)는 다음 방정식을 만족하는 분포입니다. \[ \pi(v) = \sum_{u \to v} \frac{\pi(u)}{\deg^+(u)} \] 여기서 \( \deg^+(u) \)는 \( u \)에서 나가는 링크의 수, 합은 \( v \)로 들어오는 링크의 출발지 \( u \) 전체에 대한 것입니다.

식을 보면 핵심이 보여요. 페이지 \( v \)의 점수는 \( v \)로 링크를 거는 페이지들이 자기 점수를 자기의 외부 링크 수만큼 나눠서 \( v \)에 보태주는 합입니다. 큰 사이트가 적은 외부 링크로 \( v \)를 가리키면 점수가 크게 옮겨오고, 외부 링크가 산만하게 많은 페이지가 \( v \)를 가리키면 조금만 옮겨와요. 추천하는 사람이 신뢰할 만하고, 또 신중할수록 추천이 무겁다는 직관이 그대로 식이 된 것이죠.

노트: 막다른 골목과 텔레포트

실제 웹은 외부 링크가 하나도 없는 페이지(dangling nodes)도 있고, 작은 그룹끼리 서로 링크하며 외부와 단절된 함정도 있어요. 단순 임의 보행은 이런 곳에 빠지면 평형이 깨집니다. 구글의 해법은 우아해요. 매 단계 \( 1 - d \)의 확률(보통 \( d = 0.85 \))로 외부 링크를 따라가지만, 확률 \( d \)... 잠깐, 부호 헷갈리지 말고 다시 — 확률 \( d \approx 0.85 \)로 링크를 따라가고, \( 1-d \approx 0.15 \)의 확률로는 아무 페이지로나 텔레포트합니다. 이렇게 하면 그래프가 완전히 연결되고 비주기적이라 평형이 보장돼요.

정리 21.2.6 (PageRank, 텔레포트 포함)

감쇠 인자 \( d \in (0, 1) \)와 균등 분포 \( \mathbf{1}/|V| \)에 대해 \[ \pi(v) = \frac{1-d}{|V|} + d \sum_{u \to v} \frac{\pi(u)}{\deg^+(u)} \] 를 만족하는 유일한 확률 분포 \( \pi \)가 존재합니다. 이 \( \pi \)가 PageRank 점수예요.

어떻게 계산하느냐고요? 방법은 놀랍게도 단순합니다. 모든 \( \pi(v) \)를 \( 1/|V| \)로 초기화한 뒤, 위의 식을 우변에서 좌변으로 반복 대입합니다 — 이걸 거듭제곱 반복(power iteration)이라고 불러요. 수십 번 반복이면 수렴합니다. 1998년 당시 웹 페이지가 수억 개였는데도 이 방법이 통했다는 게 PageRank의 공학적 묘미예요.

예제 21.2.7 (작은 웹의 PageRank 한 바퀴)

세 페이지 \( A, B, C \)와 링크 \( A \to B, A \to C, B \to C, C \to A \)를 생각해 봅시다. 외부 링크 수는 \( \deg^+(A) = 2 \), \( \deg^+(B) = 1 \), \( \deg^+(C) = 1 \). 텔레포트를 잠깐 무시하면 평형 방정식은 \[ \pi(A) = \pi(C), \quad \pi(B) = \pi(A)/2, \quad \pi(C) = \pi(A)/2 + \pi(B). \] \( \pi(A) + \pi(B) + \pi(C) = 1 \)과 함께 풀면 \( \pi(A) = 2/5 \), \( \pi(B) = 1/5 \), \( \pi(C) = 2/5 \).

직관적으로 \( C \)는 들어오는 링크가 \( A \)와 \( B \) 둘 다라 무겁고, \( A \)는 \( C \)에서 받는 100% 추천 덕에 가장 중요한 페이지 중 하나가 됩니다. \( B \)는 \( A \)의 절반짜리 추천만 받기에 점수가 작죠. 식 한두 줄로 직관이 양적으로 바뀝니다.

PageRank의 진정한 천재성은 검색 결과를 전역적으로 정렬할 점수를 검색어와 무관하게 미리 계산해 둘 수 있다는 거예요. 사용자가 검색어를 입력하면 해당 검색어에 부합하는 페이지들 중 PageRank가 높은 순서로 보여주면 그만이거든요. "임의 보행의 평형 분포"라는 한 줄짜리 수학적 객체가 검색 엔진을 살리고 구글이라는 회사를 만들어낸 셈이에요.

노트: 임의 보행이 풀어주는 다른 문제들

PageRank 말고도 임의 보행은 의외로 많은 곳에 등장합니다. SAT 해법의 무작위 워크 알고리즘, 마르코프 연쇄 몬테카를로(MCMC)로 베이즈 추론하기, 그래프의 클러스터링(이웃에 머무는 시간이 길면 같은 클러스터), 추천 시스템의 사용자–아이템 이분그래프 위 보행으로 유사도 계산하기. 공통점은 하나예요. "멀리 있는 정보를 한 걸음씩 확률적으로 모아온다"는 발상. 이 한 가지 발상으로 우리는 도박장과 검색 엔진과 신경망 학습을 같은 언어로 말할 수 있게 되었어요. 단순한 동전 던지기에서 시작한 이야기치고는 꽤 멀리 왔습니다.

PART V — 점화식

22 점화식 Recurrences

재귀는 사이즈가 작아진 자기 자신으로 답한다. 점화식은 그 답을 손으로 잡는 도구입니다. 이번 장에서는 하노이의 탑처럼 재귀가 자연스럽게 등장하는 문제부터, 합병 정렬 같은 분할정복 알고리즘의 비용을 셈하는 방법까지 차근차근 따라갑니다. 마지막에는 마스터 정리와 점화식을 다루는 실전 감각을 익혀, 알고리즘을 보고 즉시 복잡도를 가늠할 수 있는 근육을 만들어 봅니다.

22.1 하노이의 탑 The Towers of Hanoi

점화식 이야기를 시작할 때 거의 모든 교재가 꺼내드는 단골손님이 있습니다. 바로 하노이의 탑입니다. 세 개의 막대 \( A, B, C \)가 있고, 막대 \( A \)에 크기가 서로 다른 원반 \( n \)개가 큰 것이 아래, 작은 것이 위로 쌓여 있어요. 우리는 이 원반들을 모두 막대 \( C \)로 옮겨야 합니다. 단, 규칙이 있습니다.

  • 한 번에 원반은 하나만 움직일 수 있다.
  • 큰 원반을 작은 원반 위에 올릴 수 없다.

이 문제의 매력은, 답을 머리로 풀려고 하면 금방 막히는데 재귀로 풀면 거짓말처럼 풀린다는 점입니다. 한번 같이 따라가 봐요.

핵심 아이디어는 이렇습니다. \( n \)개를 \( A \to C \)로 옮기고 싶으면, 먼저 위쪽 \( n-1 \)개를 \( A \to B \)로 옮긴 다음, 가장 큰 \( n \)번 원반을 \( A \to C \)로 옮기고, 마지막으로 \( B \)에 쌓아둔 \( n-1 \)개를 \( B \to C \)로 옮기면 됩니다. 큰 원반은 깔개 역할만 하므로 작은 원반들의 이동을 방해하지 않아요.

초기                  중간                  최종
 |       |       |     |       |       |     |       |       |
 _       |       |     |       |       |     |       |       _
__       |       |     |       _       |     |       |       __
___      |       |     |       __      |     |       |       ___
A        B       C     A       B       C     A       B       C
    

이 전략을 비용으로 바꿔 적으면 점화식이 됩니다. \( n \)개를 옮기는 데 필요한 최소 이동 횟수를 \( T(n) \)이라 하면, 위 절차에서 우리는 \( n-1 \)개 옮기기를 두 번, 그리고 가장 큰 원반 한 번을 옮깁니다.

정의 22.1.1 (하노이의 탑 점화식)

원반 \( n \)개를 옮기는 최소 이동 횟수 \( T(n) \)은 다음을 만족합니다.

\[ T(n) = 2T(n-1) + 1 \quad (n \ge 1), \qquad T(0) = 0. \]

점화식이 있으면 작은 값부터 직접 계산해 볼 수 있어요. \( T(0)=0,\; T(1)=1,\; T(2)=3,\; T(3)=7,\; T(4)=15,\; T(5)=31 \). 패턴이 보이나요? 1씩 더하면 모두 2의 거듭제곱입니다. 그럼 한번 추측해 봅시다. \( T(n) = 2^n - 1 \).

정리 22.1.2 (하노이 폐형식)

모든 \( n \ge 0 \)에 대해 \( T(n) = 2^n - 1 \).

증명 (귀납법)

기저 \( n=0 \)에서 \( T(0)=0=2^0-1 \). 귀납 가정으로 \( T(n-1)=2^{n-1}-1 \)이라 두면,

\[ T(n) = 2T(n-1) + 1 = 2(2^{n-1}-1) + 1 = 2^n - 2 + 1 = 2^n - 1. \]

따라서 모든 \( n \ge 0 \)에 대해 성립합니다.

여담으로, 전설에 따르면 64개 원반을 어떤 사원의 승려들이 옮기고 있다고 합니다. 1초에 한 번씩 옮긴다 해도 \( 2^{64}-1 \approx 1.8 \times 10^{19} \)초, 약 5849억년이 걸립니다. 우주의 나이보다 훨씬 길죠. 알고리즘 시간복잡도가 왜 중요한지 이보다 직관적인 예가 있을까요.

노트: 풀이 한 줄짜리 코드

재귀로 옮기는 절차를 그대로 옮기면 다음과 같습니다. 정의가 곧 코드라는 점이 재귀의 매력이에요.

def hanoi(n, src, via, dst):
    if n == 0: return
    hanoi(n-1, src, dst, via)
    print(f"{src} -> {dst}")
    hanoi(n-1, via, src, dst)

22.2 합병 정렬 Merge Sort

이제 좀 더 실용적인 친구를 봅시다. 합병 정렬(merge sort)은 \( n \)개의 원소를 정렬할 때, 배열을 절반으로 나눠 각각 정렬한 뒤 두 정렬된 부분을 합쳐 하나로 만드는 알고리즘이에요. 이 "나눠서 풀고 합친다"는 패턴이 바로 분할정복(divide-and-conquer)입니다.

비용을 \( T(n) \)이라 하면, 길이 \( n \) 배열에서 합병 정렬은 다음 일을 합니다.

  1. 길이 \( n/2 \)짜리를 두 번 정렬: 비용 \( 2T(n/2) \).
  2. 두 정렬된 배열을 하나로 합치는 merge: 비용 \( \Theta(n) \) (양쪽 끝에서 작은 쪽을 한 번씩 뽑아내며 \( n \)개 다 채우면 끝).

정의 22.2.1 (합병 정렬 점화식)

\[ T(n) = 2\,T(n/2) + n \quad (n \ge 2), \qquad T(1) = 0. \]

여기서 \( n \)이 2의 거듭제곱이라 가정해도 결과의 점근적 차수는 같습니다.

이 점화식을 손으로 풀어 봅시다. 가장 단순한 방법은 펼쳐쓰기(unrolling)입니다. 한 단계씩 안쪽으로 들어가면서 식을 풀어 보면,

\[ T(n) = 2T(n/2) + n = 2\big(2T(n/4) + n/2\big) + n = 4T(n/4) + 2n. \]

한 번 더 펼치면 \( 8T(n/8) + 3n \). \( k \)번 펼치면 \( 2^k T(n/2^k) + k\,n \). 이제 \( n/2^k = 1 \)이 될 때까지, 즉 \( k = \log_2 n \)까지 가면,

\[ T(n) = 2^{\log_2 n}\, T(1) + (\log_2 n)\, n = n \cdot 0 + n \log_2 n = n \log_2 n. \]

정리 22.2.2 (합병 정렬 비용)

\( T(n) = 2T(n/2) + n,\; T(1)=0 \)이면 \( T(n) = \Theta(n \log n) \).

같은 결과를 그림으로도 볼 수 있어요. 재귀 트리(recursion tree)를 그려 봅시다. 루트에서 비용 \( n \), 다음 층에 비용 \( n/2 \)인 노드 두 개(합 \( n \)), 그 다음에 \( n/4 \)인 노드 네 개(합 \( n \))… 층마다 합이 \( n \)인 게 핵심입니다. 트리의 높이는 \( \log_2 n \)이므로 전체 비용은 \( n \log_2 n \).

            n            ← n
          /   \
        n/2    n/2        ← n
       / \    / \
     n/4 n/4 n/4 n/4      ← n
      ...                 ← ...
      1 1 1 ... 1         ← n  (leaves: 총 n개)
    높이 log₂ n
    

예제 22.2.3

\( n=8 \)이라 하자. 펼쳐쓰기로 \( T(8) = 2T(4) + 8 = 2(2T(2) + 4) + 8 = 4T(2) + 16 = 4(2T(1)+2) + 16 = 8T(1) + 8 + 16 = 0 + 24 \). 한편 \( n \log_2 n = 8 \cdot 3 = 24 \)로 정확히 일치합니다.

노트: 비교 정렬의 한계

비교만 가지고 정렬하는 모든 알고리즘은 \( \Omega(n \log n) \) 시간이 걸린다는 게 정보이론적으로 알려져 있습니다. 합병 정렬은 그 하한을 점근적으로 달성하는 깔끔한 알고리즘이라 두고두고 등장해요.

22.3 선형 점화식 Linear Recurrences

하노이는 \( T(n) = 2T(n-1)+1 \), 합병 정렬은 \( T(n) = 2T(n/2) + n \). 둘 다 자기 자신을 다시 부르지만, 부르는 방식이 다릅니다. 이 절에서는 첫 번째 종류, 즉 입력 크기를 상수만큼 줄이는 점화식을 정리합니다. 일반적으로 모양은

\[ a_n = c_1 a_{n-1} + c_2 a_{n-2} + \cdots + c_d a_{n-d} + f(n) \]

이고, 계수 \( c_i \)가 상수일 때 이를 상수계수 선형 점화식이라고 합니다. \( f(n)=0 \)이면 동차(homogeneous), 아니면 비동차(inhomogeneous)입니다.

정의 22.3.1 (특성 방정식)

동차 점화식 \( a_n = c_1 a_{n-1} + \cdots + c_d a_{n-d} \)에 \( a_n = r^n \)을 대입하면 양변을 \( r^{n-d} \)로 나눠 다음을 얻습니다.

\[ r^d - c_1 r^{d-1} - c_2 r^{d-2} - \cdots - c_d = 0. \]

이 다항식을 특성 방정식, 그 근을 특성근이라 부릅니다.

특성근을 \( r_1, \ldots, r_d \)라 하고 모두 다르다면, 일반해는 이들의 선형결합입니다.

\[ a_n = \alpha_1 r_1^n + \alpha_2 r_2^n + \cdots + \alpha_d r_d^n. \]

계수 \( \alpha_i \)는 초기조건(\( a_0, a_1, \ldots \))을 대입해 연립방정식으로 정합니다. 만약 어떤 근 \( r \)이 중근이라면 \( r^n,\, n r^n,\, n^2 r^n,\ldots \) 식으로 \( n \)을 곱한 항들을 추가해 주면 됩니다.

예제 22.3.2 (피보나치)

\( F_n = F_{n-1} + F_{n-2},\; F_0 = 0,\; F_1 = 1 \). 특성 방정식은 \( r^2 - r - 1 = 0 \), 근은 \( r = (1\pm\sqrt5)/2 \). 흔히 \( \varphi = (1+\sqrt5)/2 \), \( \psi = (1-\sqrt5)/2 \)라 쓰면 일반해는 \( F_n = \alpha \varphi^n + \beta \psi^n \).

\( F_0=0 \)에서 \( \alpha + \beta = 0 \), \( F_1=1 \)에서 \( \alpha\varphi + \beta\psi = 1 \)을 풀면 \( \alpha = 1/\sqrt5,\; \beta = -1/\sqrt5 \). 따라서 비네 공식

\[ F_n = \frac{\varphi^n - \psi^n}{\sqrt5}. \]

\( |\psi| < 1 \)이라 큰 \( n \)에서 \( F_n \approx \varphi^n/\sqrt5 \). 정수 수열인데 무리수가 등장하는 게 늘 신기하죠.

비동차 항 \( f(n) \)이 있을 때는 두 단계로 나눕니다. 먼저 동차 부분의 일반해 \( a_n^{(h)} \)를 구하고, \( f(n) \)에 어울리는 특수해 \( a_n^{(p)} \)를 추측해서 대입해 본 뒤, 둘을 더한 \( a_n = a_n^{(h)} + a_n^{(p)} \)로 일반해를 만듭니다.

비동차항 \( f(n) \)특수해 추측
상수 \( c \)상수 \( A \)
다항식 \( n^k \)같은 차수의 다항식 \( A_k n^k + \cdots + A_0 \)
지수 \( c\,b^n \) (\( b \)가 특성근이 아닐 때)\( A b^n \)
지수 \( c\,b^n \) (\( b \)가 특성근일 때)\( A n b^n \)

예제 22.3.3 (하노이 다시 보기)

\( T_n = 2T_{n-1} + 1 \). 동차 부분 \( T_n - 2T_{n-1} = 0 \)의 특성근은 \( r = 2 \), 동차해는 \( T_n^{(h)} = \alpha \cdot 2^n \). 비동차항이 상수이므로 특수해를 \( T_n^{(p)} = A \)로 추측. 대입하면 \( A = 2A + 1 \), \( A = -1 \). 일반해는 \( T_n = \alpha \cdot 2^n - 1 \). 초기조건 \( T_0=0 \)에서 \( \alpha = 1 \). 결과는 \( T_n = 2^n - 1 \). 22.1절의 답과 똑같죠.

노트

"왜 \( a_n = r^n \)을 시도하나?" 직관은 이렇습니다. \( a_n = r \cdot a_{n-1} \) 같은 1차 점화식이라면 답이 정확히 \( r^n \) 꼴이라는 걸 우리는 압니다. 차수가 높아져도 그 기본형의 합으로 표현된다는 게 선형성의 본질이에요. 미분방정식에서 \( e^{rx} \)를 시도하는 것과 정확히 같은 발상입니다.

22.4 분할정복 점화식 Divide-and-Conquer Recurrences

합병 정렬 같은 알고리즘의 비용은 일반적으로 다음 모양을 합니다.

\[ T(n) = a\,T(n/b) + f(n), \]

여기서 \( a \ge 1 \)은 부분문제 개수, \( b > 1 \)은 크기 축소 비율, \( f(n) \)은 분할과 결합에 드는 비용이에요. 이런 점화식의 차수를 한 방에 알려주는 도구가 바로 마스터 정리(Master Theorem)입니다.

정리 22.4.1 (마스터 정리)

\( T(n) = a\,T(n/b) + f(n) \), \( a \ge 1,\; b > 1 \), \( f(n) \)은 양의 함수라 하자. \( n^{\log_b a} \)와 \( f(n) \)의 점근적 크기를 비교한다.

  1. 경우 1. 어떤 \( \varepsilon > 0 \)에 대해 \( f(n) = O(n^{\log_b a - \varepsilon}) \)이면 \( T(n) = \Theta(n^{\log_b a}) \).
  2. 경우 2. \( f(n) = \Theta(n^{\log_b a}) \)이면 \( T(n) = \Theta(n^{\log_b a} \log n) \).
  3. 경우 3. 어떤 \( \varepsilon > 0 \)에 대해 \( f(n) = \Omega(n^{\log_b a + \varepsilon}) \)이고, 적당한 \( c < 1 \)이 있어 \( a f(n/b) \le c f(n) \)이면 \( T(n) = \Theta(f(n)) \).

왜 이런 모양이 나오는지 직관은 재귀 트리에 있습니다. 트리의 높이는 \( \log_b n \), \( k \)번째 층에는 노드가 \( a^k \)개, 각 노드의 비용이 \( f(n/b^k) \)예요. 잎의 개수는 \( a^{\log_b n} = n^{\log_b a} \). 따라서 비용이 어디에 몰리는지가 차수를 결정합니다.

  • 경우 1: 잎 쪽이 무겁다. 합병 비용이 작아 잎이 비용을 지배 → \( n^{\log_b a} \).
  • 경우 2: 모든 층이 비슷하게 무겁다. 층마다 \( \Theta(n^{\log_b a}) \), 층이 \( \log n \)개 → \( n^{\log_b a} \log n \).
  • 경우 3: 루트 쪽이 무겁다. 루트의 \( f(n) \)이 비용을 지배 → \( f(n) \).

예제 22.4.2

(a) 합병 정렬: \( T(n) = 2T(n/2) + n \). \( a=b=2 \)이므로 \( n^{\log_b a} = n^1 = n \). \( f(n) = n \)도 같으므로 경우 2에 해당, \( T(n) = \Theta(n \log n) \).

(b) 이진 탐색: \( T(n) = T(n/2) + 1 \). \( a=1,\; b=2 \)이므로 \( n^{\log_b a} = n^0 = 1 \), \( f(n) = 1 \)도 같으므로 경우 2, \( T(n) = \Theta(\log n) \).

(c) 스트라센 행렬곱: \( T(n) = 7T(n/2) + n^2 \). \( n^{\log_2 7} \approx n^{2.807} \)이고 \( f(n) = n^2 \)이 그보다 다항적으로 작으므로 경우 1, \( T(n) = \Theta(n^{\log_2 7}) \). 표준 행렬곱의 \( \Theta(n^3) \)보다 빠릅니다.

(d) 퀵셀렉트의 가장 좋은 분기: \( T(n) = T(n/2) + n \). \( n^{\log_b a} = 1 \), \( f(n) = n \)이 다항적으로 더 크므로 경우 3, \( T(n) = \Theta(n) \).

노트: 빠지기 쉬운 함정

경우 1과 3은 "다항적으로(\( n^\varepsilon \)만큼) 차이가 나야" 적용됩니다. 가령 \( T(n) = 2T(n/2) + n \log n \)에서 \( n^{\log_2 2} = n \)과 \( n \log n \)은 다항적 차이가 아니라 로그 차이뿐이라 마스터 정리 표준 형태로는 풀리지 않아요. 이런 경계 사례에는 펼쳐쓰기가 직접 도움이 됩니다(답은 \( \Theta(n \log^2 n) \)).

22.5 점화식 감각 익히기 A Feel for Recurrences

점화식을 잘 다루는 사람은 정리 하나를 외우고 있는 사람이 아니라, 답의 모양을 빠르게 추측하고 검증하는 사람입니다. 이 절에서는 그 감각을 위한 세 가지 도구를 정리합니다.

(1) 펼쳐쓰기(unrolling). 점화식을 한두 단계 풀어쓰고 패턴을 찾는 방법이에요. 22.2절에서 \( T(n) = 2T(n/2)+n \)을 펼쳐 \( 2^k T(n/2^k) + kn \) 꼴을 얻은 게 전형적인 예입니다. 일반항을 추측한 뒤, 귀납법으로 검증하면 끝.

(2) 재귀 트리(recursion tree). 부분문제를 트리로 그리고, 층별 비용을 합산하는 방법. 분할정복 점화식의 직관은 거의 항상 트리에서 옵니다. 마스터 정리의 세 경우도 결국 "어느 층이 비용을 지배하는가?"의 트리적 표현이에요.

(3) 추측-검증(guess and verify). 답이 \( O(n \log n) \)일 거라고 추측한 뒤, 강한 귀납법으로 \( T(n) \le c\,n \log n \)을 직접 증명하는 방법. 이걸 치환법(substitution method)이라고도 부릅니다. 추측만 적당히 하면 거의 모든 점화식을 잡을 수 있어요.

예제 22.5.1 (치환법)

\( T(n) = 2T(n/2) + n,\; T(1) = 1 \)에 대해 \( T(n) \le c n \log_2 n \)을 적당한 \( c \)에 대해 보이자. 귀납 가정: \( T(n/2) \le c\,(n/2) \log_2(n/2) \). 그러면

\[ T(n) \le 2 \cdot c (n/2)\log_2(n/2) + n = c n (\log_2 n - 1) + n = c n \log_2 n - c n + n. \]

이게 \( c n \log_2 n \) 이하이려면 \( -cn + n \le 0 \), 즉 \( c \ge 1 \). 기저는 \( n=2 \)에서 직접 확인하면 끝. 이렇게 추측 → 대입 → 부등식 정리만 하면 점화식이 풀립니다.

마지막으로 점화식을 만났을 때 머릿속에 둘 만한 실전 팁입니다.

  • 점화식을 보자마자 "크기를 어떻게 줄이는가"를 묻자. \( n-1 \)인지, \( n/b \)인지에 따라 도구가 달라진다.
  • 크기가 상수만큼 줄면(예: \( T(n)=T(n-1)+\cdots \)) 선형 점화식 도구(특성방정식)를 시도.
  • 크기가 비율로 줄면(예: \( T(n)=aT(n/b)+f(n) \)) 마스터 정리부터 본다.
  • 마스터 정리가 안 되면 재귀 트리를 그려본다. 거의 항상 답이 보인다.
  • 그래도 안 풀리면 답의 형태를 추측하고 치환법으로 검증한다.
  • 작은 \( n \)에 대해 직접 계산해 보고 OEIS(온라인 정수수열 사전)에 검색해 보는 것도 의외로 빠른 길이다.

마무리 노트

점화식은 알고리즘 분석에서 가장 자주 만나는 도구입니다. 함수의 클로즈드 폼(닫힌 형태)을 항상 구할 필요는 없어요. 우리가 보통 알고 싶은 건 차수 \( \Theta(\cdot) \)뿐이니까요. 이번 장의 도구—펼쳐쓰기, 트리법, 특성방정식, 마스터 정리, 치환법—은 그 차수를 빠르게 잡아내는 다섯 자루의 칼입니다. 알고리즘 책을 읽다 점화식을 마주치면, 다섯 칼 중 어느 것이 어울릴지 한번씩 떠올려 보세요. 손이 풀리는 데에는 시간이 걸리지만, 한 번 풀리면 평생을 갑니다.