경고 : 최신판이 아닙니다. 이 문서의 오래된 판을 편집하고 있습니다. 이것을 저장하면, 이 판 이후로 바뀐 모든 편집이 사라집니다. 로그인하고 있지 않습니다. 편집하면 당신의 IP 주소가 공개적으로 기록됩니다. 계정을 만들고 로그인하면 편집 시 사용자 이름만 보이며, 위키 이용에 여러 가지 편의가 주어집니다.스팸 방지 검사입니다. 이것을 입력하지 마세요!Dynamic Programming, DP. == 개요 == 동적 계획법은 어떤 최적화 문제를, 작은 부분 문제로 나누어 차례대로 해결하는 알고리즘을 말한다. 이름이 Dynamic Programming이지만 그닥 역동적인 알고리즘은 아닌데, [[예산]]을 따오기 위해 멋진 이름을 지었다고 카더라(...). 또한 Programming은 컴퓨터 프로그래밍을 의미하는 것이 아니고, [[선형계획법]]처럼 최적화 문제의 해결 방법이라는 의미이다. == 예시 == 그냥 이론을 설명하기에는 복잡하니, 예시를 보며 이해해 보자. === 피보나치 수열 구하기 === [[피보나치 수열]]은 제 0항을 0, 제 1항을 1로 하고, 그 다음 항부터는 이전 두 개 항의 합으로 나타나는 수열이다. 이를 점화식으로 표현하면 <math> \mathrm{fib}(n) = \mathrm{fib}(n - 1) + \mathrm{fib}(n - 2) (n > 2), \mathrm{fib}(0) = 0, \mathrm{fib}(1) = 1 </math>가 된다. 이를 계산하는 프로그램을 작성해 보자. 점화식에 충실하게 재귀함수로 풀면 다음과 같을 것이다. 편의상 [[Python]]3으로 작성하였다. <pre> def fib(n): if n == 1 or n == 0: return n return fib(n - 1) + fib(n - 2) </pre> 분명 잘 작동하긴 하는데, 문제는 숫자가 조금만 커져도 시간이 너무 오래 걸린다는 점이다. <math> \mathrm{fib}(5) </math>의 계산 과정을 그림으로 그려보면 다음과 같다. [[파일:Fib(5).png]] 위의 동그라미는 아래 두 개의 동그라미의 합으로 채워진다. 얼마나 많은 계산이 필요한지 알 수 있다. 그런데 저 계산들 중 중복되는 것이 보이지 않는가? 저 과정에서 <math> \mathrm{fib}(2) </math>는 3번, <math> \mathrm{fib}(3) </math>는 2번 계산됨을 알 수 있다. 이걸 일일히 계산하지 말고, 한번 구한 값을 그냥 어디 적어(memo)놨다가 다시 쓰면 어떨까? 이 기법이 바로 메모화(memoization)이다. 저 그림의 맨 왼쪽 아래부터 계산하기 시작해보자. <math> \mathrm{fib}(2) = 1 + 0 = 1 </math>로 채워진다. 그 위의 <math> \mathrm{fib}(3) = 1 + 1 = 2 </math>가 될 것이다. 이제 <math> \mathrm{fib}(4) </math>를 계산해야 한다. 원래는 <math> \mathrm{fib}(4) = 2 + \mathrm{fib}(2) </math>로 오른쪽의 <math> \mathrm{fib}(2) </math>를 다시 계산해야겠지만, 앞서 <math> \mathrm{fib}(2) </math>를 계산할 때 어디 적어뒀다면 이를 바로 읽어와 <math> \mathrm{fib}(4) = 2 + 1 = 3 </math>을 간단히 계산할 수 있다. 마찬가지로, <math> \mathrm{fib}(5) </math>의 계산 역시 <math> \mathrm{fib}(3) </math>의 계산 결과가 저장되어 있다면, 곧바로 <math> \mathrm{fib}(5) = 3 + 2 = 5 </math>라는 값을 구할 수 있다. 메모하지 않았다면 <math> \mathrm{fib}(3), \mathrm{fib}(2) </math> 따위를 여러번 다시 구해야 할 판인데, 계산이 확 줄어들었다. 코드로 적으면 다음과 같다. <pre> def fib(n): DT = [None] * (n + 1) DT[0], DT[1] = 0, 1 return cal_fib(DT, n) def cal_fib(DT, n): if DT[n] == None: DT[n] = cal_fib(DT, n - 1) + cal_fib(DT, n - 2) return DT[n] </pre> ==== 시간 복잡도 분석 ==== 우선 메모화를 적용하지 않고 계산했을 때의 시간 복잡도를 구해보자. 계산 시간은 그냥 동그라미 개수라고 생각해도 좋다. {| class="wikitable" ! N || 0 || 1 || 2 || 3 || 4 || 5 || 6 |- | fib || 0 || 1 || 1 || 2 || 3 || 5 || 8 |- | 계산량 || 1 || 1 || 3 || 5 || 8 |} N이 1일 때를 제외하고, 각 N에 대해 계산량이 <math> \mathrm{fib}(N+2) </math> 임이 보인다. [[big-O 표기법]]에 따르면 <math> O(\mathrm{fib}(n)) </math> 인데, 좀 큰 <math> n </math> 에 대해 <math> \mathrm{fib}(n) \approx 1.6^n </math> 이므로, <math> O(1.6^n) </math>로 쓸 수 있다. 지수함수라는 놈이 얼마나 흉악한 놈인지는 다들 알겠지만 한번 짚어보자. <math> n = 100 </math>정도만 생각해봐도 대충 <math> 1.6^{100} = 2.6 \times 10^{20} </math>쯤 되는데, 이건 컴퓨터가 뚝딱 계산할 수 있는 양이 아니다. 요즘 CPU 클럭수가 대략 4GHz, 초당 <math> 4 \times 10^9 </math>회니까, 65,000,000,000초, 752314일쯤 걸리지 않을까? 물론 시간복잡도에 숫자 때려넣은 걸 클럭수로 나눈 것과 실제 수행 시간이 일치하지는 않지만, 대충 감은 잡을 수 있다. === 거스름돈 문제 === 리브레 제국의 화폐 체계는 영 이상해서, 이 나라의 상인들은 거스름돈 계산을 힘들어 한다. 국왕인 당신은 이러한 백성들을 어엿비 녀겨 거스름돈을 계산하는 프로그램을 만들기로 결심했다. 이 나라에는 <math> x_1 </math>원, <math> x_2 </math>원, <math> \cdots , x_i </math>원 짜리 동전이 있고, 거슬러 주는 동전의 개수는 최대한 줄여야 한다. ==== Top-down method ==== ==== Bottom-up method ==== === 행렬을 곱하는 순서 === 행렬을 곱할 때, 어떤 것을 먼저 곱하는지에 따라 계산량은 크게 달라진다. 계산을 가능한 한 적게 할 수 있도록, 적절히 괄호를 묶어주기 위한 알고리즘을 생각해보자. [[분류:알고리즘]] 요약: 리브레 위키에서의 모든 기여는 크리에이티브 커먼즈 저작자표시-동일조건변경허락 3.0 라이선스로 배포됩니다(자세한 내용에 대해서는 리브레 위키:저작권 문서를 읽어주세요). 만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요. 글이 직접 작성되었거나 호환되는 라이선스인지 확인해주세요. 리그베다 위키, 나무위키, 오리위키, 구스위키, 디시위키 및 CCL 미적용 사이트 등에서 글을 가져오실 때는 본인이 문서의 유일한 기여자여야 하고, 만약 본인이 문서의 유일한 기여자라는 증거가 없다면 그 문서는 불시에 삭제될 수 있습니다. 취소 편집 도움말 (새 창에서 열림) | () [] [[]] {{}} {{{}}} · <!-- --> · [[분류:]] · [[파일:]] · [[미디어:]] · #넘겨주기 [[]] · {{ㅊ|}} · <onlyinclude></onlyinclude> · <includeonly></includeonly> · <noinclude></noinclude> · <br /> · <ref></ref> · {{각주}} · {|class="wikitable" · |- · rowspan=""| · colspan=""| · |} {{lang|}} · {{llang||}} · {{인용문|}} · {{인용문2|}} · {{유튜브|}} · {{다음팟|}} · {{니코|}} · {{토막글}} {{삭제|}} · {{특정판삭제|}}(이유를 적지 않을 경우 기각될 가능성이 높습니다. 반드시 이유를 적어주세요.) {{#expr:}} · {{#if:}} · {{#ifeq:}} · {{#iferror:}} · {{#ifexist:}} · {{#switch:}} · {{#time:}} · {{#timel:}} · {{#titleparts:}} __NOTOC__ · __FORCETOC__ · __TOC__ · {{PAGENAME}} · {{SITENAME}} · {{localurl:}} · {{fullurl:}} · {{ns:}} –(대시) ‘’(작은따옴표) “”(큰따옴표) ·(가운뎃점) …(말줄임표) ‽(물음느낌표) 〈〉(홑화살괄호) 《》(겹화살괄호) ± − × ÷ ≈ ≠ ∓ ≤ ≥ ∞ ¬ ¹ ² ³ ⁿ ¼ ½ ¾ § € £ ₩ ¥ ¢ † ‡ • ← → ↔ ‰ °C µ(마이크로) Å °(도) ′(분) ″(초) Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ(뮤) Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω · Ά ά Έ έ Ή ή Ί ί Ό ό Ύ ύ Ώ ώ · Ϊ ϊ Ϋ ϋ · ΐ ΰ Æ æ Đ(D with stroke) đ Ð(eth) ð ı Ł ł Ø ø Œ œ ß Þ þ · Á á Ć ć É é Í í Ĺ ĺ Ḿ ḿ Ń ń Ó ó Ŕ ŕ Ś ś Ú ú Ý ý Ź ź · À à È è Ì ì Ǹ ǹ Ò ò Ù ù · İ Ż ż ·  â Ĉ ĉ Ê ê Ĝ ĝ Ĥ ĥ Î î Ĵ ĵ Ô ô Ŝ ŝ Û û · Ä ä Ë ë Ï ï Ö ö Ü ü Ÿ ÿ · ǘ ǜ ǚ ǖ · caron/háček: Ǎ ǎ Č č Ď ď Ě ě Ǐ ǐ Ľ ľ Ň ň Ǒ ǒ Ř ř Š š Ť ť Ǔ ǔ Ž ž · breve: Ă ă Ğ ğ Ŏ ŏ Ŭ ŭ · Ā ā Ē ē Ī ī Ō ō Ū ū · à ã Ñ ñ Õ õ · Å å Ů ů · Ą ą Ę ę · Ç ç Ş ş Ţ ţ · Ő ő Ű ű · Ș ș Ț ț