Recursive Algorithm fibn if n 1 or n
피보나치수를 구하는 Recursive Algorithm fib(n) { if (n = 1 or n = 2) then return 1; else return (fib(n-1) +fib(n-2)); } ü 엄청난 중복 호출이 존재한다 - 7 -
피보나치 수열의 Call Tree fib(7) fib(6) fib(5) fib(4) fib(3) fib (2) fib(3) fib(2) fib (1) fib(3) fib (2) fib(1) fib(4) fib(2) fib (1) fib (2) fib(3) fib(2) fib (1) 중복 호출의 예 - 8 - fib(1)
유효한 이동의 예 6 7 12 5 5 3 11 18 7 17 3 3 8 10 14 9 - 13 -
Recursive Algorithm matrix. Path(i, j) ▷ (i, j)에 이르는 최저점수 { if (i = 1 and j = 1) then return mij; else if (i = 1) then return (matrix. Path(1, j-1) + mij); else if (j = 1) then return (matrix. Path(i-1, 1) + mij); else return ((min(matrix. Path(i-1, j), matrix. Path(i, j-1)) + mij); } - 14 -
mat(4, 4) mat(4, 3) mat (4, 2) mat(2, 1) mat(1, 1) mat(3, 1) mat(2, 3) mat(3, 2) mat(4, 1) mat(3, 3) mat(2, 1) mat(1, 2) mat(1, 1) mat(2, 2) mat(3, 1) mat(2, 2) mat(1, 3) mat(1, 2) mat(2, 1) mat(1, 2) mat(1, 1) mat(1, 1) mat(3, 4) mat(2, 4) mat(1, 3) mat(1, 2) mat(1, 1) mat(2, 3) mat(1, 4) mat(1, 3) Call Tree mat(3, 3) mat(2, 2) mat(1, 2) mat(2, 1) mat(1, 2) mat(1, 1) mat(1, 1) - 15 - mat(3, 2) mat(1, 3) mat(3, 1) mat(1, 2) mat(2, 1) mat(1, 1) mat(2, 2) mat(2, 1) mat(1, 2) mat(1, 1)
DP matrix. Path(i, j) ▷ (i, j)에 이르는 최저점수 { c[1, 1] ← m 11 ; for i ← 2 to n c[i, 1] ← mi 1 + c[i-1, 1]; for j ← 2 to n c[1, j] ← m 1 j + c[1, j-1]; for i ← 2 to n for j ← 2 to n c[i, j] ← mij + min(c[i-1, j], c[i, j-1]); return c[n, n]; } üComplexity: O(n 2) - 16 -
테이블의 예 6 7 12 -5 5 3 11 3 -8 10 14 9 7 13 8 5 11 12 4 8 -2 9 4 7 - 18 -
합법적인 예 6 7 12 -5 5 3 11 3 -8 10 14 9 7 13 8 5 11 12 7 4 8 -2 9 4 합법적이지 않은 예 6 7 12 -5 5 3 11 3 -8 10 14 9 7 13 8 5 11 12 7 4 8 -2 9 4 Violation! - 19 -
i-1 6 7 12 -5 … i 5 -5 3 11 3 -8 10 14 9 7 13 8 5 11 12 7 8 4 -2 4 4 i 열과 i-1열의 관계를 파악해 보자 - 22 - 9
peb(5, 1) Call Tree peb(4, 3) peb (3, 1) peb(3, 2) peb(2, 1) peb(2, 2) peb(2, 3) peb(1, 1)peb(1, 3) peb(1, 4) peb(1, 1) peb(1, 2) peb(2, 3) peb(1, 2) peb(1, 3) peb(1, 1) peb(1, 2) peb(4, 2) peb (3, 1) peb(2, 2) peb(3, 3) peb(2, 1) peb(3, 4) peb(2, 2) peb(1, 1)peb(1, 3) peb(1, 4) peb(1, 1) peb(1, 2) peb(1, 3) - 25 - peb(2, 2) peb(1, 1) peb(1, 3) peb(1, 4) peb(2, 4) peb(1, 2)
DP pebble. Sum(n) { for p ← 1 to 4 peb[1, p] ← w[1, p] ; for i ← 2 to n { for p ← 1 to 4 { peb[i, p] ← w[i, p] + max {peb[i-1, q]} ; 패턴 q는 패턴 p와 양립 } return max { peb[n, p] } ; } p =1, 2, 3, 4 ü복잡도 : O(n) - 27 -
Complexity pebble. Sum(n) 기껏 4 바퀴 무시 { 기껏 n 바퀴 for p ← 1 to 4 peb[1, p] ← w[1, p] ; for i ← 2 to n { for p ← 1 to 4 { peb[i, p] ← w[i, p] + max {peb[i-1, q]} ; 패턴 q는 패턴 p와 양립 } return max { peb[n, p] } ; } p =1, 2, 3, 4 기껏 3 가지 n * 4 * 3 = O (n ) üComplexity: O(n) - 28 -
Recursive Algorithm r. Matrix. Chain(i, j) ▷ 행렬곱 을 구하는 최소 비용 구하기 { if (i = j) then return 0; ▷ 행렬이 하나뿐인 경우의 비용은 0 min ← ∞; for k ← i to j-1 { q ← r. Matrix. Chain(i, k) + r. Matrix. Chain(k+1, j) + pi-1 pkpj; if (q < min) then min ← q; } return min; } ü 엄청난 중복 호출이 발생한다! - 32 -
DP matrix. Chain(1, n) (i, j) { for i ← 1 to n m[i, i] ← 0; ▷ 행렬이 하나뿐인 경우의 비용은 0 for r ← 1 to n-1 ▷ 문제의 크기 = r+1 for i ← 1 to n-r { j ← i+r; m[i, j] ← min {m[i, k] + m[k+1, j] + pi-1 pkpj}; i ≤ k ≤ j-1 } return m[1, n]; ü Complexity: Θ(n 3) } r= 1 i = 1 2 … n-1 j=2 3…n r= 2 i = 1 2 … n-2 j=3 4…n - 33 - … r= n-1 i=1 j=n
문제 예 4: Longest Common Subsequence(LCS) • 두 string에 공통적으로 들어있는 common subsequence 들 중 가장 긴 것을 찾는다 • Subsequence의 예 – <bcdb>는 문자열 <abcbdab>의 subsequence이다 • Common subsequence의 예 – <bca>는 문자열 <abcbdab>와 <bdcaba>의 common subsequence 이다 • Longest common subsequence(LCS) – Common subsequence들 중 가장 긴 것 – 예: <bcba>는 string <abcbdab>와 <bdcaba>의 LCS이다 - 34 -
Optimal Substructure • 두 string Xm = <x 1 x 2 … xm>과 Yn = <y 1 y 2 … yn>에 대해 – xm= yn이면 Xm과 Yn의 LCS의 길이는 Xm-1과 Yn-1의 LCS의 길이보다 1 이 크다 – xm≠ yn이면 Xm과 Yn의 LCS의 길이는 Xm과 Yn-1의 LCS의 길이와 Xm-1 과 Yn의 LCS의 길이 중 큰 것과 같다 • cij = 0 if i = 0 or j = 0 ci-1, j-1 + 1 if i, j > 0 and xi= max{ci-1, j, ci, j-1} yj if i, j > 0 and xi ≠ yj ü cij : 두 문자열 Xi = <x 1 x 2 … xi>과 Yj = <y 1 y 2 … yj>의 LCS 길이 - 35 -
Recursive Algorithm LCS(m, n) ▷ 두 문자열 Xm과 Yn의 LCS 길이 구하기 { if (m = 0 or n = 0) then return 0; else if (xm= yn) then return LCS(m-1, n-1) + 1; else return max(LCS(m-1, n), LCS(m, n-1)); } ü 엄청난 중복 호출이 발생한다! - 36 -
LCS(3, 4) LCS(3, 3) LCS(3, 2) LCS(2, 3) LCS(2, 2) LCS(1, 3) LCS(0, 3) LCS(1, 2) LCS(2, 2) LCS(3, 1) LCS(2, 1) LCS(3, 0) LCS(2, 1) LCS(1, 2) LCS(2, 1) LCS(0, 2) LCS(1, 1) LCS(2, 0) LCS(1, 1) LCS(0, 1) LCS(1, 0) LCS(0, 1) LCS(1, 0) LCS(2, 4) LCS(2, 3) LCS(1, 4) LCS(0, 4) LCS(1, 3) Call Tree LCS(2, 2) LCS(1, 3) LCS(0, 3) LCS(1, 2) LCS(2, 1) LCS(0, 2) LCS(1, 1) LCS(2, 0) LCS(1, 1) LCS(0, 1) LCS(1, 0) - 37 - LCS(0, 1) LCS(1, 0)
DP LCS(m, n) ▷ 두 문자열 Xm과 Yn의 LCS 길이 구하기 { for i ← 0 to m C[i, 0] ← 0; for j ← 0 to n C[0, j] ← 0; for i ← 1 to m for j ← 1 to n if (xm= yn) then C[i, j] ← C[i-1, j-1] + 1; else C[i, j] ← max(C[i-1, j], C[i, j-1]); return C[m, n]; } ü Complexity: Θ(mn) - 38 -
Recursive Relation dtk = min {drk-1+ wr, t} for all edges (r, t) ds 0 = 0; dt 0 = ∞; - 41 -
DP Ballman-Ford(G, s) { ds ← 0; for all vertices i ≠ s di ← ∞; for k ← 1 to n-1 { for all edges (a, b) { if (da + wa, b < db ) then db ← da + wa, b ; } a } } ü Propagation 되는 모습이 떠오르면 잘 이해한 것! - 42 - b
(a) 8 ∞ ∞ -15 0 9 11 1 5 -12 ∞ ∞ 3 ∞ 8 8 ∞ (f) i =5 8 -15 9 3 11 10 8 1 5 -7 6 11 8 -8 9 3 0 8 8 16 - 43 - ∞ 11 9 3 9 11 4 8 8 (d) i =3 4 4 8 6 11 19 -6 -15 0 2 1 5 -12 12 -7 -6 -15 0 2 10 -15 11 4 -7 ∞ 0 2 9 8 8 8 (e) i =4 1 -12 0 11 10 ∞ 1 5 -12 ∞ 9 3 4 -15 0 11 -7 9 11 ∞ (c) i =2 8 10 -15 0 2 8 (b) i =1 8 10 9 3 11 7 8 8 19 10 10 2 1 5 -12 19 -7 ∞ 4 10 4 2 1 5 -12 12 -7 4 12
(f) i =5 8 9 3 1 (g) i =6 8 10 -15 9 3 11 -3 10 6 4 (h) i =7 8 10 1 1 -12 5 -7 3 11 -18 9 3 4 -5 1 -12 9 11 7 - 44 - 5 -7 8 6 11 -18 9 3 -5 1 -12 9 11 4 10 -15 0 2 3 8 8 (i) 10 -15 0 2 3 8 8 5 -7 -15 0 2 9 8 8 나중에 그래프 알고리즘 부분에서 다시 한 번 생각할 기회가 있음 1 -12 0 11 11 10 -15 0 11 -15 7 5 3 8 8 2 -7 4 6
Thank you - 45 -
- Slides: 45