preface - 기쉬운...orithm 제2장알고리즘 ... 2013년1월 저자양성봉. 6 contents alg...

31

Upload: vankien

Post on 10-Feb-2018

221 views

Category:

Documents


4 download

TRANSCRIPT

3

PR

EF

AC

EALGORITHM

컴퓨터를 전공하는 부분의 학생들에게 알고리즘의 이해는 만만치 않은 어려움

을 주는 것 같다. 필자의 경험에 비추어볼 때, 알고리즘의 어려움은 여러 다양한 경

우들을 조목조목‘따져보는’논리적 검토 과정에서 비롯되는 것으로 보인다. 그러

나 실제 알고리즘은 컴퓨터 분야뿐만 아니라 과학, 공학, 경 학 등 광범위한 분야

에서 나타나는 많은 중요한 문제들을 해결하는 기본적인 방법들과 직간접적으로 관

련되어 있어, 반드시 이해하고 숙달할 필요가 있다.

본서는 필자가 지난 20년간의 강의 경험을 바탕으로 알고리즘 이해에 있어 가장

기본적이고 공통된 부분을 발췌, 정리하 다. 독자들의 쉬운 이해를 위해 각 알고리

즘에 해 다음의 네 가지 단계를 염두에 두고 설명하 다.

1. 주어진 문제에 한 이해와 분석

2. 알고리즘의 핵심 아이디어 유추

3. 알고리즘 소개 및 단계별 설명

4. 예제 따라 알고리즘 이해하기

주어진 문제가 어떤 특성을 가졌는지를 분석해보면 그 문제를 해결할 알고리즘

을 고안하는 실마리를 찾을 수 있다. 이를 통해 알고리즘의 핵심 아이디어를 유추해

보면, 알고리즘을 보다 쉽게 이해할 수 있다. 또한 예제를 통해 알고리즘의 수행과

정을 상세히 step-by-step으로 보임으로써 알고리즘을 완전히 이해할 수 있도록

하 다. 아울러 시간복잡도를 분석하고, 알고리즘의 효용성을 위해 알고리즘이 실

제로 활용되는 사례들을 설명하 다.

본서의 각 장의 내용을 소개하면 다음과 같다.

제1장알고리즘의첫걸음

이미 우리가 알고 있는 알고리즘들부터 수수께끼같이 재미있는 문제에 한 알

고리즘들을 살펴본다.

머리말

문제분석

핵심아이디어

알고리즘

알고리즘�수행과정상세한

알고리즘�응용실세계

4

PR

EF

AC

EA

LG

OR

ITH

M

제2장알고리즘을배우기위한준비

알고리즘이란 무엇인가를 알아보고, 최초의 알고리즘인 유클리드의 최 공약수

알고리즘을 소개하며, 3장부터 다루는 알고리즘들을 배울 준비를 위한 알고리즘의

표현방법, 알고리즘의 분류, 알고리즘의 효율성 표현 방법, 복잡도의 점근적 표기를

소개하고, 마지막으로 왜 효율적인 알고리즘이 필요한가를 설명한다.

제3장분할정복알고리즘

분할 정복(Divide-and-Conquer) 알고리즘으로 해결되는 문제들을 소개하고, 그

에 한 알고리즘들을 설명한다. 합병 정렬(Merge sort), 퀵 정렬(Quick sort), 선택

(Selection) 문제, 최근접 점의 쌍(Closest Pair) 찾기 문제를 다룬다.

제4장그리디알고리즘

그리디(Greedy) 알고리즘은 top-down 방식으로 최적화 문제를 해결하는 알고리

즘이다. 동전 거스름돈(Coin Change), 최소 신장 트리(Minimum Spanning Tree),

최단 경로(Shortest Path), 부분 배낭(Fractional Knapsack) 문제, 집합 커버(Set

Cover), 작업 스케줄링(Task Scheduling), 허프만 압축(Huffman Encoding)에 한

그리디 알고리즘을 각각 소개한다.

제5장동적계획알고리즘

동적 계획(Dynamic Programming) 알고리즘은 최적화 문제를 해결하는 bottom-up

방식의 알고리즘이다. 모든 쌍 최단 경로(All Pairs Shortest Paths), 연속 행렬 곱셈

(Chained Matrix Multiplication), 편집 거리(Edit Distance) 문제, 배낭(Knapsack) 문

제, 동전거스름돈(Coin Change) 문제의동적계획알고리즘을소개한다.

제6장정렬알고리즘

기본적인 정렬 알고리즘인 버블 정렬(Bubble sort), 선택 정렬(Selection sort),

삽입 정렬(Insertion sort)을 다루고, 이보다 효율적인 쉘 정렬(Shell sort)과 힙 정렬

(Heap sort)을 살펴보며, 특정 환경에서 사용되는 기수 정렬(Radix sort)과 외부정

렬(External sort)을 소개한다.

제7장NP-완전문제

앞장에서 소개된 부분의 문제들은 다항식 시간복잡도의 알고리즘으로 해결되

나, 실세계에서 많이 응용되는 중요한 문제들은 그러하지 못하다. 이러한 문제들 중

5

PR

EF

AC

EALGORITHM

에서 표적인 NP-완전 문제들을 이해하고, 그 문제들 간의 관계를 살펴본다.

제8장근사알고리즘

지수 시간복잡도를 가진 NP-완전 문제들에 한 정확한 해보다는 근사 해

(approximation solution)를 찾는 알고리즘들을 소개한다. 이를 위해 여행자 문제

(Traveling Salesman Problem), 정점 커버(Vertex Cover) 문제, 통 채우기(Bin

Packing) 문제, 작업 스케줄링(Job Scheduling) 문제, 클러스터링(Clustering) 문제

의 근사 알고리즘을 각각 알아본다.

제9장해탐색알고리즘

NP-완전 문제의 해를 탐색하기 위한 다양한 알고리즘을 소개한다. 백트래킹

(Backtracking) 기법, 분기 한정(Branch-and-Bound) 기법, 유전자 알고리즘

(Genetic Algorithm), 모의 담금질(Simulated Annealing) 기법을 소개한다.

이 책은 자료구조에 한 기본 개념을 갖춘 학부 3, 4학년 학생들을 위하여 집필

되었으나, 올림피아드와 같은 경시 회를 준비하는 학생들에게도 도움이 될 것이

다. 또한 전자공학, 수학, 경 학을 전공하는 학생들에게는 알고리즘을 스스로 배우

고 익힐 수 있는 좋은 입문서가 되리라 생각한다. 독자들이 알고리즘의 기본 개념을

이해함으로써 궁극적으로는 실세계의 어떤 문제가 주어지더라도 그 문제를 분석하

고 해결할 수 있는 능력을 가질 수 있게 되기를 바라는 마음이다.

책이 완성되는 과정에서 많은 사람들의 도움을 받았다. 일일이 다 열거할 수는

없지만, 마지막 단계에서 원고를 꼼꼼히 읽고 검토해준 유용현 군과 장기 , 양원석

군의 도움에 고마움을 표한다. 또한 책 쓸 것을 제안하시고, 풍부한 저작활동 경험

으로 지속적인 조언을 아끼지 않으신 같은 학과 최윤철 교수님과 한탁돈 교수님의

성원에 깊은 감사를 드린다. 아울러 이 책의 시작과 완성의 전 과정을 이끌어 주신

생능출판사 김승기 사장님과 출판 과정에서 여러 가지로 애써 주신 출판사 관계자

분들께도 진심으로 감사드린다.

2013년 1월

저자 양성봉

6

CO

NT

EN

TS

AL

GO

RIT

HM

1.1 최 숫자 찾기 13

1.2 임의의 숫자 찾기 13

1.3 동전 거스름돈 15

1.4 한붓그리기 17

1.5 미로 찾기 18

1.6 가짜 동전 찾기 20

1.7 독이 든 술단지 23

■ 요약 28

■ 연습문제 29

2.1 알고리즘이란 34

2.2 최초의 알고리즘 36

2.3 알고리즘의 표현 방법 37

2.4 알고리즘의 분류 39

2.5 알고리즘의 효율성 표현 40

2.6 복잡도의 점근적 표기 42

2.7 왜 효율적인 알고리즘이 필요한가? 47

■ 요약 48

■ 연습문제 50

알고리즘의 첫걸음

차례

CHAPTER

01

알고리즘을 배우기 위한 준비CHAPTER

02

7

CO

NT

EN

TS

ALGORITHM

3.1 합병 정렬 56

3.2 퀵 정렬 60

3.3 선택 문제 67

3.4 최근접 점의 쌍 찾기 74

3.5 분할 정복을 적용하는 데 있어서 주의할 점 83

■ 요약 86

■ 연습문제 87

4.1 동전 거스름돈 95

4.2 최소 신장 트리 98

4.3 최단 경로 찾기 107

4.4 부분 배낭 문제 111

4.5 집합 커버 문제 115

4.6 작업 스케줄링 122

4.7 허프만 압축 126

■ 요약 131

■ 연습문제 133

분할 정복 알고리즘CHAPTER

03

그리디 알고리즘CHAPTER

04

8

CO

NT

EN

TS

AL

GO

RIT

HM

5.1 모든 쌍 최단 경로 141

5.2 연속 행렬 곱셈 148

5.3 편집 거리 문제 159

5.4 배낭 문제 169

5.5 동전 거스름돈 179

■ 요약 191

■ 연습문제 193

6.1 버블 정렬 199

6.2 선택 정렬 203

6.3 삽입 정렬 206

6.4 쉘 정렬 210

6.5 힙 정렬 216

6.6 정렬 문제의 하한 221

6.7 기수 정렬 224

6.8 외부정렬 227

■ 요약 235

■ 연습문제 236

동적 계획 알고리즘CHAPTER

05

정렬 알고리즘CHAPTER

06

9

CO

NT

EN

TS

ALGORITHM

7.1 문제 분류 240

7.2 NP-완전 문제의 특성 243

7.3 NP-완전 문제의 소개 247

7.4 NP-완전 문제들의 활용 252

■ 요약 258

■ 연습문제 259

8.1 여행자 문제 265

8.2 정점 커버 문제 268

8.3 통 채우기 문제 271

8.4 작업 스케줄링 문제 275

8.5 클러스터링 문제 278

■ 요약 286

■ 연습문제 287

9.1 백트래킹 기법 292

9.2 분기 한정 기법 299

9.3 유전자 알고리즘 309

NP-완전 문제CHAPTER

07

근사 알고리즘CHAPTER

08

해 탐색 알고리즘CHAPTER

09

10

CO

NT

EN

TS

AL

GO

RIT

HM

9.4 모의 담금질 기법 316

■ 요약 322

■ 연습문제 323

Ⅰ. 재귀 관계의 해 구하는 방법 330

Ⅱ. 힙 자료구조 336

Ⅲ. 매칭 346

Ⅳ. 백트래킹 기법과 분기 한정기법의 추가 문제 347

■ 찾아보기 361

부록

CHAPTER01알고리즘의 첫걸음

1.1 최 숫자 찾기

1.2 임의의 숫자 찾기

1.3 동전 거스름돈

1.4 한붓그리기

1.5 미로 찾기

1.6 가짜 동전 찾기

1.7 독이 든 술단지

AL

GO

RIT

HM

Contents

알고리즘은 우리의 일상생활에서 그리 낯익은 단어는 아니

다. 알고리즘이라는 용어는 9세기경 페르시아 수학자인 알

콰리즈미(al-Khwarizmi)의 이름으로부터 유래되었다. 알고

리즘은 문제를 해결하기 위한 단계적인 절차를 의미한다. 흔

히 알고리즘은 요리법과 유사하다고 한다. 단계적인 절차를

따라 하면 요리가 만들어지듯이, 알고리즘도 단계적인 절차

를 따라 하면 주어진 문제의 답을 주기 때문이다. 주어진 문

제에 해 여러 종류의 알고리즘이 있을 수 있으나, 항상 보

다 효율적인 알고리즘을 고안하는 것이 매우 중요하다.

사실 우리는 어려서부터 적지 않은 수의 알고리즘을 접해왔다. 1장에서는 이미 우

리가 알고 있는 알고리즘부터 수수께끼같이 재미있는 문제에 한 알고리즘까지

다양한 예를 살펴보기로 하자.

12

CHAPTER

01 알고리즘의 첫걸음

▶알콰리즈미(a l-Khwarizmi, 서기780~850년)

아이들은 숫자에 한 개념을 배우고 나서, 흔히 숫자 카드놀이를 한다. 카드놀이

중에서 아주 간단한 가장 큰 숫자 찾기를 생각해보자. 카드 10장이 다음 그림과

같이 바닥에 펼쳐져 있다.

가장 큰 숫자가 적힌 카드를 찾는 한 가지 방법은 카드의 숫자를 하나씩 비교하면서

본 숫자들 중에서 가장 큰 숫자를 기억해가며 진행하는 방법일 것이다. 마지막 카드

의 숫자를 본 후에, 머릿속에 기억된 가장 큰 숫자가 적힌 카드를 바닥에서 집어

든다.

이렇게 찾는 방법을 순차탐색(Sequential Search)이라고 한다. 즉, 카드를 한 장씩

차례 로(주어진 순서 로) 읽어가며 찾는 방법이다.

두 번째 숫자 카드놀이로서 특정 숫자가 적힌 카드를 찾는 것을 생각해 보자. 45,

20, 60, 35, 10, 55, 90, 85, 75, 25가 각각 적힌 카드가 바닥에 펼쳐져 있다. 이

중에서 85가 적힌 카드를 찾아보자.

13

알고리즘의 첫걸음 01CHAPTERALGORITHM

1.1 최 숫자 찾기

문제

알고리즘

1.2 임의의 숫자 찾기

문제

최 숫자 찾기처럼 머릿속에 85를 기억하고 바닥에 펼쳐진 카드를 차례 로 한 장

씩 읽으며 85가 적힌 카드를 찾는다. 이 역시 순차탐색을 이용한 것이다.

이번에는 같은 10장의 카드가 오름차순으로 미리

정렬되어 있다고 가정하자. 우리는 이러한 경우를

실생활에서 흔히 접할 수 있는데, 사전, 휴 폰의

전화번호 리스트, 책 뒷부분의 인덱스 등을 예로 들

수 있다.

만일, 10장의 카드가 옆의 그림처럼 쌓여 있고, 첫

번째 카드의 숫자 15만 보이는 경우, 그중에서 임의

의 숫자인 85를 찾고자 할 때, 순차탐색보다 더 효

율적인 방법은 없을까? 즉, 카드가 정렬되어 있다는

정보를 어떻게 활용할 수 있을까?

15, 20, 25, 35, 45, 55, 60, 75, 85, 90에서 85를 순차탐색으로 찾을 경우, 앞쪽

에 있는 8장의 카드를 읽은 후에나 85를 찾는다. 그러나 카드가 정렬되어 있으므

로, 만일 85가 정렬된 카드의 뒷부분에 있는 것이 확실하면 앞부분은 탐색할 필요

가 없다. 그러면 위의 예제에서 85가 뒷부분에 있다는 것을 어떻게 알 수 있을까?

중간에 있는 카드의 숫자인 45(혹은 55)와 85를 한 번만 비교해보면 된다.

14

알고리즘ALGORITHM

핵심아이디어

알고리즘

문제85를 어떻게찾지?

순차탐색으로 1번 비교 후 이진탐색으로 1번 비교 후

중간 카드 한 장을 읽어 85와 비교해보는 것이 첫 카드부터 읽어 나가는 순차탐색

보다 훨씬 빠르게 목표(85가 적힌 카드)에 다가감을 알 수 있다.

이처럼 오름차순으로 정렬된 데이터를 반으로 나누고, 나누어진 반을 다시 반으로

나누고, 이 과정을 반복하여 원하는 데이터를 찾는 탐색 알고리즘을 이진탐색

(Binary Search)이라고 한다.

물건을 사고 거스름돈을 동전으로 받아야 한다면, 부분의 경우 가장 적은 수의

동전을 받기 원한다. 예를 들어, 거스름돈이 730원이라면, 500원짜리 동전 1개,

100원짜리 동전 2개, 10원짜리 동전 3개인 총 6개를 거슬러 받으면 거스름돈

730원에 한 최소 동전의 수가 된다.

15

알고리즘의 첫걸음 01CHAPTERALGORITHM

1.3 동전 거스름돈

알고리즘

문제

주어진 거스름돈에 해 어떻게 하면 가장 적은 수의 동전을 찾을까? 일반적으로

거스름돈에 해서 가장 큰 액면의 동전부터 차례로 고려한다. 730원의 거스름돈

에 해서 고려해야 할 가장 큰 액면의 동전은 500원짜리 동전이므로, 500원짜리

동전 1개를 선택한다. 이제 230원이 남아 있으므로, 다음으로 큰 액면의 동전인

100원짜리 동전 2개를 선택하고 나면, 30원이 남는다. 그 다음 큰 액면의 동전은

50원짜리 동전이나 거스름돈이 30원이므로, 50원짜리 동전은 선택할 수 없고, 마

지막으로 10원짜리 동전 3개를 선택한다. 따라서 총 동전의 수는 1+2+3 = 6개

이고, 이는 거스름돈 730원에 한 가장 적은 동전의 수이다.

동전 거스름돈 문제를 해결하는 알고리즘은 남은 거스름돈 액수를 넘지 않는 한도에

서 가장 큰 액면의 동전을 계속하여 선택하는 것이다.

이러한 종류의 알고리즘을 그리디(Greedy) 알고리즘이라고 하며, 동전 거스름돈 문

제에 한 그리디 알고리즘은 4.1절에서 보다 상세히 살펴볼 것이다.

16

알고리즘ALGORITHM

핵심아이디어

알고리즘

다음은 종이에서 연필을 떼지 않고 그리는 한붓그리기 문제이다. 한붓그리기는 그

래프의 어느 한 점에서 출발하여 모든 선분을 한 번만 지나서 출발점으로 돌아오

되, 궤적을 그리는 동안 연필이 종이에서 떨어져서는 안 된다. 단, 한 점을 여러

차례 방문하여도 괜찮다.

어떻게 한붓그리기의 해결 방법을 찾아야 할까? 그래프가 작으면 연필로 시행착

오를 통해서 해결할 수 있으나, 그래프가 크면 그래프의 어느 점까지 진행하여 왔

을 때, 다음에 어느 점으로 이동해야 할지를 결정하기가 쉽지 않다. [그림 1-1]을

살펴보자.

[그림 1-1]

17

알고리즘의 첫걸음 01CHAPTERALGORITHM

핵심아이디어

1.4 한붓그리기

문제

[그림 1-1]은 점 1에서 출발하여 점 2를 지나고, 점 3과 점 8을 거쳐서 점 7에 도

착한 상태를 나타내고 있다. [그림 1-1]에서 지나온 궤적을 굵은 선으로 보여주고

있다. 점 7이 현재 점이라 하자. 현재 점으로부터 점 6, 9 또는 10 중에서 어디로

진행해야 할까? 각 점에 해서 살펴보자.

●점 6으로 가면 5, 4, 3, 9, 7, 10을 거쳐서 점 1로 돌아올 수 있다.

●점 9로 가면 3, 4, 5, 6, 7, 10을 거쳐서 점 1로 역시 돌아올 수 있다.

●점 10으로 가면, 점 1로 갈 수밖에 없고 3, 4, 5, 6, 7, 9 사이의 선분을 지나가기

위해서는 연필을 떼어야만 한다.

어떻게 하면 현재 점에서 점 10으로 진행하지 않고, 점 6이나 점 9로 진행해야만 한

다는것을알수있을까? 점 6과점 9로갈경우의공통점은점 7(즉, 현재점)이다.

따라서 이 질문에 한 답은 현재 점으로부터 진행하고자 하는 점을 지나서 현재 점

으로 돌아오는 사이클(cycle)을 찾는 것이다.

현재 점 7에서 점 10을 지나서 현재 점으로 돌아오는 사이클은 없다. 왜냐하면 그러

기 위해서는 점 1, 2, 3, 8을 지나가야 하는데 이 점들 사이의 선분은 이미 지나갔기

때문이다. 그러나 현재 점으로부터 점 6이나 점 9를 지나서 현재 점으로 돌아오는

사이클이 있다. 따라서 현재 점에서 점 6이나 점 9를 선택하면, 연필을 떼지 않고

진행할 수 있다.

미로를 찾는 문제는 그리스 신화에서 유래된

다. 당시 지중해의 크레타 섬을 통치하던 폭

군 미노스(Minos) 왕이 있었다. 미노스 왕은

황소 머리에 하반신은 사람인 무서운 짐승

미노타우로스(Minotauros)에게 제물로 받치

기 위해 아테네의 젊은 남녀를 조공으로 요

구하 다. 조공으로 바쳐진 젊은이들은 지하

18

알고리즘ALGORITHM

1.5 미로 찾기

알고리즘

문제

에 있는 매우 광 하고 복잡한 미로 내부에 갇혔고, 그들은 미로를 탈출하지 못하

면 미노타우로스에게 잡히어 먹혔다.

이러한 비극이 계속되는 동안, 아테네의 한 젊은

청년 테세우스(Theseus)는 자발적으로 제물이 되

기로 결심하여 조공으로 바쳐졌다. 그는 다행히

미노스 왕의 딸 아리아드네(Ariadne)의 충고로

칼과 함께 실타래를 가지고 실을 풀면서 미로에

들어갔다. 그리고 마침내 테세우스는 미노타우로

스를 칼로 죽이고, 실을 다시 감으면서 미로를 빠져나왔다. 이 그리스 신화에서 알

려주는 미로 찾기의 해는 바로 실타래이다.

그런데 부분의 경우는 실타래나 도와주는 사람도 없다. 이러한 상황에서 어떻게

미로를 빠져나올 수 있을까?

일반적인 방법은 현 위치에서 한 방향을 선

택하여 이동하고, 길이 막혀 있으면 다시 되

돌아 나오며, 다른 방향으로 다시 시도해 보

는 것이다. 가능하다면 지나갔던 곳을 표시

해놓고 다시 안 가면 된다. 그러나 사실 이

방법은 그리스 신화 속의 미로에서는 불가능

하다. 지하의 미로에서는 빛이 없어서 표시

한 곳을 식별할 수 없다.

그러나 이렇게 어려운 상황에서도 답은 존재

한다. 이는 바로 오른손 법칙이다.

현 위치에서 한 방향을 선택하고, 벽에 오른손

을 댄다. 그리고 출구가 나올 때까지 계속 오

른손을 벽에서 떼지 않고 걸어간다.

이 방법은 실타래나 특별한 표시가 필요 없이

항상 출구를 찾게 해준다. [그림 1-2]는 오른

손 법칙 알고리즘으로 출구를 찾아 나아가는

궤적을 점선으로 보여주고 있다.

19

알고리즘의 첫걸음 01CHAPTERALGORITHM

알고리즘

문제

[그림 1-2]

아주 많은 동전 더미 속에 1개의 가짜 동

전이 섞여 있다. 그런데 이 가짜 동전은

매우 정교하게 만들어져 누구도 눈으로

가짜인지를 식별할 수 없다. 그러나 가짜

동전의 무게는 정상적인 동전보다 약간

가볍다. 가짜 동전 찾기 문제는 이 가짜

동전을 찾아내기 위해서 양팔 저울만 사

용하여 가짜 동전을 찾아내는 것인데, 가

능한 한 저울에 동전을 다는 횟수를 줄여

야 한다.

양팔 저울은 저울 양쪽에 올려놓은 것이 같은 무게인지 아닌지 만을 판별해준다.

따라서 동전 더미를 분할하여, 저울에 올려서 한쪽으로 기우는지 아닌지를 알아내

어 가짜 동전을 가려내야한다.

철수의 생각: 임의의 동전 1개를 저울 왼편에 올리고, 나머지 동전을 하나씩 오른

편에 올려서 가짜 동전을 찾아보자.

20

알고리즘ALGORITHM

핵심아이디어

1.6 가짜 동전 찾기

문제과연 양팔 저울로 가짜 동전을 찾아낼 수있을까?

임의의 동전 1개를 저울

왼편에, 나머지 동전을

하나씩 오른편에

올려서 가려내어 보자.

철수의 제안은 운이 좋으면 1번만에 가짜 동전을 찾는다. 왼편에 미리 올려놓은

동전이 가짜이거나, 아니면 오른편에 처음으로 올려놓은 동전이 가짜인 경우이다.

그러나 최악의 경우는 가장 마지막에 가짜 동전을 저울 오른편에 올려놓게 되는

경우이다. 이 경우는 만일 총 동전 수가 n이라면 (n-1)번 저울을 재야 한다. 1을

뺀 이유는 동전 하나를 저울의 왼편에 미리 올려놓았기 때문이다.

희의 생각: 동전을 2개씩 짝을 지어, n/2 짝을 각각 저울에 달아서 가짜 동전을

찾아보자.

희의 제안도 운이 좋으면 첫 번째 짝을 저울에 올렸을 때 가벼운 쪽의 동전이 가

짜임을 알 수 있다. 최악의 경우는 동전이 짝수 개이면 가장 마지막 짝을 잴 때 불

균형이 일어나는 경우이고, 동전이 홀수 개이면 모든 짝이 균형을 이루어 진짜 동

전임을 확인하고 남은 1개의 동전이(저울에 잴 필요 없이) 가짜임을 알 수 있는 경

우이다. 따라서 최 약 n/2번의 저울을 재야 한다. 희의 알고리즘은 철수의 알

고리즘에 비해 최악의 경우 저울에 다는 횟수가 거의 1/2로 줄었다.

광수의 생각: 희의 제안을 보면 짝의 수가 너무 많다. 먼저 동전 더미를 반(두

짝)으로 나누어 저울 양편에 놓으면 어떨까?

21

알고리즘의 첫걸음 01CHAPTERALGORITHM

동전을 2개씩

짝지어 저울에

달아보자.

광수의 제안은 한 번에 어느 쪽에 가짜 동전이 있는지 알 수 있다. 그 다음에는 가

벼운 쪽을 다시 반씩 나누어 저울에 잰다.

이렇게 하다보면 남은 동전 수는 계속 1/2로 줄어들게 되고, 나중에 2개가 남았을

때 가짜 동전을 가려낼 수 있다.

22

알고리즘ALGORITHM

희의 제안을 보면 너무 여러번 시행해야 해서 번거롭네. 먼저동전 더미를 반으로 나누어 저울양편에 놓으면 어떨까?

동전 더미를 반으로 나누어 저울에 달고, 가벼운 쪽의 더미를 계속 반으로 나누어

저울에 단다. 분할된 더미의 동전 수가 1개씩이면, 마지막으로 저울을 달아 가벼운

쪽의 동전이 가짜임을 찾아낸다.

광수의 알고리즘은 운이 좋을 때가 없다. 왜냐하면 마지막에 가서야 가짜 동전을

찾기 때문이다. 그러면 광수 알고리즘은 동전이 1,024개 있을 때 몇 번 저울에 달

아야 할까? 먼저 512개씩 양쪽에 올려놓고 저울을 재고, 다음은 256개씩 재고,

128개씩, 64개씩, 32개씩, 16개씩, 8개씩, 4개씩, 2개씩, 마지막엔 1개씩 올려서

저울을 잰다. 이는 총 10번이고(log21,024 = 10이므로), 일반적인 n에 해서는

log2n번이다. 최악의 경우 철수는 1,023번 저울에 달아야 하고, 희는 512번 달

아야 하는데, 광수는 10번이면 가짜 동전을 찾는다. 이 차이는 n이 커지면 더욱

더 커진다.

옛날 어느 먼 나라에 술을 매우 즐겨 마시는 임금님이 살고 있었

다. 그래서 창고에는 많은 술단지가 보관되어 있다. 그런데 어느

날 이웃 나라의 스파이가 창고에 들어가서 술단지 하나에 독을 넣

고 나오다가 붙잡혔다. 스파이를 추궁하여 어느 단지에 독을 넣었

는지 알아내려고 하 으나, 스파이는 눈으로 확인할 수 없는 독을

사용하 고, 어떤 단지인지는 모르지만 하나의 단지에만 독을 넣

었다고 실토하고는 숨을 거두었다. 스파이가 사용한 독의 특징은 독이 든 단지의

술을 아주 조금만 맛보아도 술을 맛본 사람은 정확히 일주일 후에 죽는다는 것

이다.

임금님은 독이 든 술단지를 반드시 일주일 만에 찾아내라고 신하들에게 명하 다.

문제는 희생되는 신하의 수를 줄이는 것이다.

23

알고리즘의 첫걸음 01CHAPTERALGORITHM

1.7 독이 든 술단지

알고리즘

문제

어떻게 하면 독이 든 술단지를 일주일 만에 찾아낼 수 있을까? 이러한 문제 해결

의 핵심은 적은 수의 술단지에 해서 생각해 보는 것이다. 즉, 술단지의 수가 2개

일 때, 4개일 때 문제를 풀어 보고, 술단지의 수를 늘려가면서 일반적인 규칙을 찾

아보는 것이다.

입력의 크기가 아주 작을 때에 문제의 답을 찾아서 힌트를 얻자.1)

술단지가 2개 있다고 생각해 보자.

한 명의 신하가 하나의 술단지의 술

을 맛보고 일주일 후 살아 있으면 맛

보지 않은 단지에 독이 있는 것이고,

죽는다면 맛본 술단지에 독이 들어

있는 것이다.

이번에는 술단지가 4개 있다고 생각

해보자. 이제 신하 한 사람으로는 모

자라고 적어도 두 사람이 필요하다.

24

알고리즘ALGORITHM

핵심아이디어

힌트

1) 이 아이디어는 부분의 경우 주어진 문제를 위한 알고리즘을 고안할 때, 또는 주어진 알고리즘을

이해하려고 할 때 매우 중요한 역할을 한다.

에잇! 이왕 먹는거내가 다 마신다.

제…제가언제요?

네가 먼저 마셔봐. 마누라보다술이 좋다며!

철수의 제안: 두 사람이 각각 한 단지씩 맛보게 하자.

문제점: 두 사람이 맛보지 않은 나머지 2개의 단지 중 하나에 독이 들어 있으면,

일주일 후 두 사람은 살아 있을 것이고, 나머지 2개의 단지 중 어느 하나에 독이

들어 있는지를 알 수 없다.

광수의 제안: 4개의 단지를 2개의 그룹으로 나누어, 각 그룹에 한 사람씩 할당한

다. 이 경우는 맨 처음 고려했던 술단지의 수가 2인 경우가 2개가 생긴 셈이다. 과

연 답을 찾을 수 있을까?

25

알고리즘의 첫걸음 01CHAPTERALGORITHM

잔인한 놈. 야! 네가마셔봐!

각각 술 한 단지씩맛을 보세요!

문제점: 일주일 후에 만일 두 사람 다 살아 있으면, 어떤 단지가 독이 들어 있단 말

인가? 각 그룹에서 맛을 안 본 단지가 하나씩 있으므로, 이 2개의 단지 중 하나에

독이 들어 있는 것이다. 그러나 어느 단지인지를 알려면 또 일주일이 필요하므로

광수의 제안 역시 실패이다.

광수의 제안을 어떻게 보완해야 할까? 아니면 새로운 방법을 찾아야 하나? 이를

위해 다시 한 번 문제를 살펴보자. 우리가 혹시 문제에서 간과한 점이 있나, 아니

면 문제에 없는 조건을 우리 마음 로 만들었는지를 생각해보자.

부분의 경우에 한 신하가 반드시 하나의 단지의 술만 맛보아야 하는 것으로 생

각하기 쉽다. 문제에는 이러한 조건이 주어지지 않았다. 이것이 바로 문제 해결의

실마리가 된다.

광수의 제안에서 총 4개의 단지 중에 시음하지 않은 2개의 단지가 있다. 이 2개의

단지 중에 하나를 두 신하에게 동시에 맛을 보게 하는 것이다. 이렇게 하면 다음과

같이 4가지의 결과가 생긴다. 두 신하를 각각 A와 B라고 하자.

●아무도 시음하지 않은 단지에 독이 있으면, 일주일 후에 두 신하 모두 다 살아

있다.

●A가 혼자 시음한 단지에 독이 있으면, 일주일 후에 A만 죽는다.

●B가 혼자 시음한 단지에 독이 있으면, 일주일 후에 B만 죽는다.

●A와 B 둘 다 시음한 단지에 독이 있으면, 일주일 후에 둘 다 죽는다.

26

알고리즘ALGORITHM

4개의 단지를 2개의 그룹으로 나누어 각 그룹에 한사람씩 할당해 봅시다.

그러면 단지 수가 많을 때에는 어떻게 해야 할까? 그 아이디어는 각 단지에 2진수

를 0부터 부여하고, 각 신하가 술 맛을 보면 1 안 보면 0으로 하여, 다음과 같이 단

지와 신하를 짝지어 보는 것이다.

[그림 1-3]

[그림 1-3]에서 단지의 번호를 00부터 11의 2진수로 각각 표기한 것을 주목해 보

자. 여기서 누가 어느 단지의 술을 맛볼 것인가에 한 규칙을 알 수 있다. A는 오

른쪽 비트가 1인 단지 01과 단지 11을 맛보고, B는 왼쪽 비트가 1인 단지 10과 단

지 11을 맛본다.

술단지가 8개인 경우에는, 다음과 같이 술 단지를 2진수로 000부터 111로 표기

하면, 각각의 2진수는 3개의 자릿수로 표현된다. 즉, 술단지 4개의 경우처럼, 1개

의 자릿수마다 한 명의 신하를 할당한다. 다음과 같이 첫 번째 비트는 C, 두 번째

비트는 B, 마지막 비트는 A에 할당한다.

따라서 독이 든 술단지 찾기 문제에 한 답은 먼저 술단지 개수를 2진수로 표기

하여 각 비트당 1명의 신하를 할당한다. 그런 후 각 신하는 자신이 할당 받은 비트

가 1인 단지들을 모두 맛보게 한다. 일반적으로 n개의 단지가 있으면 log2n명의

신하를 위와 같은 방법으로 시음하게 하면, 일주일 후에 반드시 독이 든 술단지를

찾을 수 있고, 최소의 희생자 수는 0명이고, 최 는 log2n명이다.

단지신하

0 0 0 0 0 1

A

0 1 0

B B B

0 1 1

A

1 0 0

C C C BC

1 0 1

A

1 1 0 1 1 1

A

27

알고리즘의 첫걸음 01CHAPTERALGORITHM

알고리즘

●순차탐색(Sequential Search): 주어진 순서에 따라 차례로 탐색한다.

●이진탐색(Binary Search): 정렬된 데이터에 해서 중간에 있는 데이터를 비교

하여 그 결과에 따라 같으면 탐색을 마치고, 다르면 작은 데이터가 있는 쪽 또는

큰 데이터가 있는 쪽을 같은 방식으로 탐색한다.

●동전 거스름돈 문제에서 가장 액면이 높은 동전을 항상 선택(그리디하게 선택)

한다. 그리디(Greedy) 알고리즘은 4장에서 다룬다.

●한붓그리기 문제는 오일러 서킷(Euler Circuit) 문제와 같다. 알고리즘의 핵심은

현재 점에서 다음으로 이동 가능한 점을 선택할 때에는 반드시 현재 점으로 돌

아오는 사이클이 존재하여야 한다는 것이다.

●가짜 동전 찾기에서 동전 더미를 반으로 분할하여 저울에 달고, 가짜 동전이 있

는 더미를 계속해서 반으로 나누어 저울에 단다. 이는 분할 정복(Divide-and-

Conquer) 알고리즘의 일종이며, 분할 정복 알고리즘에 해서는 3장에서 상세

히 설명한다.

●독이 든 술단지 문제는 2진수를 활용하여 그 해를 찾는다.

28

알고리즘ALGORITHM

요약

1. 1.1절에서 설명된 최 숫자 찾기 문제에 한 알고리즘과 다른 알고리즘을

생각해 보자.

2. 여러 장의 숫자 카드 중에서 가장 큰 수와 가장 작은 수를 동시에 찾기 위한

알고리즘을 생각해 보자.

3. 보간탐색(Interpolation Search)이 어떤 방식의 탐색인지를 조사해보자.

4. 다음의 숫자들에 해 35를 이진탐색으로 찾는 과정을 보이라.

[10, 20, 25, 35, 45, 55, 60, 75, 80, 90, 95]

5. 1,024개의 정렬된 데이터에 해 이진탐색을 하는 데 필요한 최 비교 횟수

를 구하라.

6. 순차탐색, 보간탐색, 이진탐색 중 데이터가 어떻게 주어질 때 각각 가장 빨리

찾고, 어떤 경우에 가장 늦게 찾는지를 알아보자.

7. 다음의 그래프에서 한붓그리기를 위한 궤적을 그리라.

29

알고리즘의 첫걸음 01CHAPTERALGORITHM

연습문제

8. 다음의 그래프에서는 한붓그리기를 위한 궤적을 그릴 수 없다. 그 이유를 설

명하라.

9. 다음의 그래프에서 연필을 종이에서 떼지 않고 v1에서 출발하여 모든 선분을

한 번씩 지나가며 v2까지의 궤적을 그리라.

10. 1.4절에서 설명된 한붓그리기에 한 알고리즘에서 현재 점까지 진행된 후의

그래프에서 사이클(cycle)을 찾아야 한다. 주어진 그래프에서 사이클을 찾는

방법을 설명하라.

11. 1.4절에서 설명된 한붓그리기에 한 알고리즘은 주어진 그래프에서 모든 길

(선분) 돌아오기가 가능한지를 검사하는 알고리즘으로도 사용할 수 있다. 모

든 길 돌아오기가 가능한지를 검사하는 또 다른 한붓그리기 알고리즘을 조사

해보자.

12. 한붓그리기 문제를 모든 선분 신 모든 점을 한 번만 방문하고 시작점으로

돌아오기 문제로 변형시킨다면, 이 새로운 문제는 해 토니안 사이클

30

알고리즘ALGORITHM

v1 v2

(Hamiltonian Cycle)을 찾는 문제가 된다. 이 문제에 한 알고리즘을 조사

해 보자.

13. 다음의 미로에서 오른손 법칙 알고리즘을 사용하여 출구를 찾는 궤적을 그려

라.

14. 컴퓨터 프로그래밍을 통해 미로 찾기를 해결하는 방법 2가지를 제시하라.

15. 1.6절에서 1개의 가짜 동전을 n개의 동전 중에서 찾는 데 log2n번만에 찾는

알고리즘이 설명되었다. 만일 동전의 수가 홀수 개이거나 1/2로 나누다보니

한쪽이 홀수 개 다른 한쪽이 짝수 개가 되는 경우를 처리하는 방안을 제시

하라.

16. 1.6절에서 가짜 동전을 찾는 알고리즘이 설명되었다. 이보다 더 빨리 찾는 방

법을 찾아보라[힌트: 분할되는 더미의 수를 다르게 하여 찾아보라].

17. 독이 든 술단지 문제에서 단지의 수가 3일 때 1.7절에서 설명된 알고리즘을

수행한다면, 몇 명의 신하가 필요한가? 또, 단지의 수가 각각 5, 6, 7일 때에

는 몇 명의 신하가 필요한가?

31

알고리즘의 첫걸음 01CHAPTERALGORITHM