2020-1ν•™κΈ°, λŒ€ν•™μ—μ„œ β€˜μ•Œκ³ λ¦¬μ¦˜β€™ μˆ˜μ—…μ„ λ“£κ³  κ³΅λΆ€ν•œ λ°”λ₯Ό μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€. 지적은 μ–Έμ œλ‚˜ ν™˜μ˜μž…λ‹ˆλ‹€ :)

5 minute read

2020-1ν•™κΈ°, λŒ€ν•™μ—μ„œ β€˜μ•Œκ³ λ¦¬μ¦˜β€™ μˆ˜μ—…μ„ λ“£κ³  κ³΅λΆ€ν•œ λ°”λ₯Ό μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€. 지적은 μ–Έμ œλ‚˜ ν™˜μ˜μž…λ‹ˆλ‹€ :)

<Fibonacci Number>λŠ” μž¬κ·€ ν•¨μˆ˜μ— λŒ€ν•œ κ·Όλ³ΈκΈ‰μ˜ μ£Όμ œμ΄λ‹€. 일단 μž¬κ·€μ‹ μžμ²΄κ°€ 직관적이고, 또 이것을 μ΅œμ ν™” ν•˜κΈ° μœ„ν•΄ 정말 λ§Žμ€ ν…Œν¬λ‹‰μ΄ μ œμ‹œλ˜κ³  또 μ—°κ΅¬λ˜μ—ˆλ‹€.

\[f(n) = f(n-1) + f(n-2)\]

Brute Force

κ°€μž₯ λ¨Όμ € 생각해볼 수 μžˆλŠ” 방법은 <Fibonacci Number>의 μ •μ˜μ— 맞게 ν•¨μˆ˜λ₯Ό μ§œλŠ” 것이닀. κ·Έλƒ₯ μ•„λž˜μ™€ 같이 짜면 λœλ‹€.

int fibo(n) {
  if (n <= 1) return n;
  return fibo(n-1) + fibo(n-2);
}

κ·ΈλŸ¬λ‚˜ μœ„μ˜ μ•Œκ³ λ¦¬μ¦˜μ„ 썼을 λ•Œμ˜ μ‹œκ°„ λ³΅μž‘λ„λŠ” exponential ν•˜λ‹€. πŸ€¦β€β™‚οΈ

fibo()에 μ˜ν•΄ μƒμ„±λ˜λŠ” recursion treeλ₯Ό μƒκ°ν•΄λ³΄μž. μ΄λ•Œ, tree의 leafλŠ” 항상 1을 리턴해주고 이에 따라 fibo(n)의 값은 λ‹¨μˆœνžˆ recursion tree의 leaves 수둜 μœ λ„ν•  수 μžˆλ‹€.

μ΄λ•Œ, leaf λ‹¨μ—μ„œλŠ” $O(1)$ 만큼의 μ‹œκ°„μ΄ 걸리기 λ•Œλ¬Έμ— κ²°κ΅­, $T(n) = \text{fibo}(n) \cdot O(1)$의 λ³΅μž‘λ„λ₯Ό κ°€μ§€κ²Œ λœλ‹€.

λ”°λΌμ„œ, μž¬κ·€λ‘œ κ΅¬ν˜„λœ <Fibonacci number>λŠ” κ²°κ΅­ <Fibonacci number>의 κ°’ 자체의 μ‹œκ°„ λ³΅μž‘λ„λ₯Ό κ°€μ§€κ²Œ λœλ‹€. λ”°λΌμ„œ, 이것은 λŒ€λž΅

\[\Theta \left( \left(\frac{1+\sqrt{5}}{2} \right)^n \right) = \Theta(1.6^n)\]

의 λ³΅μž‘λ„λ₯Ό 가진닀. // 보톡은 $O(2^n)$라고 λΆ€λ₯΄λŠ” 것 κ°™λ‹€.

μ΄λ ‡κ²Œ μ•Œκ³ λ¦¬μ¦˜μ΄ exponentialν•œ λ³΅μž‘λ„λ₯Ό κ°–κ²Œ 되면, μ• μ΄ˆμ— μ»΄ν“¨ν„°μ˜ κ³„μ‚°μœΌλ‘œ 감당할 μˆ˜κ°€ μ—†λ‹€. λ‹¨μˆœνžˆ $\text{Fibo}(100)$을 κ΅¬ν•˜λŠ” 데만 해도 12ζ—₯이 ν•„μš”ν•˜λ‹€. κ·Έλž˜μ„œ μ§€κΈˆμ˜ 방식은 correct ν•˜μ§€λ§Œ μ‹€μ „μ—μ„œ μ“Έ μˆ˜λŠ” μ—†λ‹€ πŸ€¦β€β™‚οΈ


DP

DPλŠ” 이 상황을 정말 μ‹œμ›ν•˜κ²Œ ν•΄κ²°ν•΄μ€€λ‹€. DPμ—μ„œλŠ” <memoization>을 톡해 κ³„μ‚°ν•œ 값을 배열에 기둝해둔닀. λ”°λΌμ„œ, λ‹€μ‹œ ν•΄λ‹Ή 값에 λŒ€ν•œ 쿼리가 듀어왔을 λ•Œ, 계산을 또 ν•˜μ§€ μ•Šκ³  배열에 μ €μž₯된 값을 λ°”λ‘œ μ‚¬μš©ν•˜κΈ°λ§Œ ν•˜λ©΄ λœλ‹€!! 😁

int memo[MAX];

int fibo(n) {
  if (n <= 1) return n;
  if (memo[n] != -1) return memo[n];
  memo[n] = fibo(n-1) + fino(n-2);
  return memo[n];
}

μ½”λ“œλ₯Ό μ΄λ ‡κ²Œ 지 경우, μš°λ¦¬λŠ” $1$λΆ€ν„° $n$κΉŒμ§€ 좔가적인 μž¬κ·€ν˜ΈμΆœ 없이 λ”± ν•œλ²ˆμ”© μˆœνšŒν•˜κ²Œ λ˜λŠ” κ²ƒμ΄λ―€λ‘œ $O(n)$의 μ‹œκ°„μ΄λ©΄ μΆ©λΆ„ν•˜λ‹€!! 😲

πŸ’₯ μ΄λ•Œ, μ£Όμ˜ν•  점은 아무리 DPλ₯Ό 쓰더라도 μž¬κ·€λ‘œ κ΅¬ν˜„ν–ˆλ‹€λ©΄, μž¬κ·€ ν•¨μˆ˜ 호좜이 1,000,000(=백만) 정도 되면 ν”„λ‘œκ·Έλž¨μ΄ μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€! 😲 κ·Έλž˜μ„œ μ™ λ§Œν•˜λ©΄, DP둜 풀더라도 μž¬κ·€λ‘œ κ΅¬ν˜„ν•˜κΈ° λ³΄λ‹€λŠ” for문으둜 적절히 λ³€ν˜•ν•΄μ„œ κ΅¬ν˜„ν•˜λŠ” κ±Έ κ°•.λ ₯. μΆ”μ²œν•œλ‹€.


Matrix-based

Property. Pisano Period

ν”Όλ³΄λ‚˜μΉ˜ 수λ₯Ό μ •μˆ˜ $K$둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λŠ” 항상 μ£ΌκΈ°λ₯Ό κ°€μ§€κ²Œ λœλ‹€. 이 μ£ΌκΈ°λ₯Ό <Pisano Period>라고 ν•œλ‹€.

Matrix-based 방법은 쒀더 큰 λ²”μœ„μ˜ ν”Όλ³΄λ‚˜μΉ˜μ˜ 수λ₯Ό λ‹€λ£° λ•Œ 더 λΉ λ₯΄κ²Œ 계산할 수 μžˆλŠ” ν…Œν¬λ‹‰μ΄λ‹€! 😲

ν”Όλ³΄λ‚˜μΉ˜ 수λ₯Ό ν–‰λ ¬λ‘œ ν‘œν˜„ν•˜λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

\[\begin{pmatrix} F_{n+2} \\ F_{n+1} \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} F_{n+1} \\ F_n \end{pmatrix}\]

μœ„μ˜ 식을 쒀더 닀듬고 μ •λ¦¬ν•˜λ©΄, μ•„λž˜μ™€ 같은 κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€. κ·Έλƒ₯ λ‹¨μˆœν•˜κ²Œ μš°λ³€μ˜ ν”Όλ³΄λ‚˜μΉ˜μ— λŒ€ν•œ 뢀뢄에 식을 λŒ€μž…ν•˜λ©΄ μ–»λŠ” 식이닀.

\[\begin{pmatrix} F_{n+1} & F_n \\ F_n & F_{n-1} \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^n\]

즉, μš°λ¦¬λŠ” ν”Όλ³΄λ‚˜μΉ˜ 수λ₯Ό μ–»κ³  μ‹Άλ‹€λ©΄, \(\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}\)λ₯Ό $n$번 κ³±ν•΄μ£Όλ©΄ λœλ‹€λŠ” 것이닀. 참고둜 이런 ν–‰λ ¬μ˜ μ œκ³±μ€ λΆ„ν•  정볡을 μ΄μš©ν•΄ $O(\log n)$λ§Œμ— 계산할 수 μžˆλ‹€!!

κ²°κ΅­, matrix-based 방식을 μ“°λ©΄, ν”Όλ³΄λ‚˜μΉ˜ 수λ₯Ό $O(\log n)$의 μ‹œκ°„ λ³΅μž‘λ„λ‘œ ꡬ할 수 μžˆλŠ” 것이닀!!! 😁

✨ 이 Matrix-based 방식은 ν”Όλ³΄λ‚˜μΉ˜ 수 뿐만 μ•„λ‹ˆλΌ λ‹€λ₯Έ μž¬κ·€ ν•¨μˆ˜ μ‹μ—μ„œλ„ λΉ„μŠ·ν•œ λ…Όλ¦¬λ‘œ μ μš©ν•  수 μžˆλ‹€!! 😁


πŸ’₯ 참고둜 ν”Όλ³΄λ‚˜μΉ˜ 수의 경우, $n=100$만 λ˜μ–΄λ„ int의 λ²”μœ„λ₯Ό λ²—μ–΄λ‚˜κ²Œ λœλ‹€. κ·ΈλŸ¬λ‹ˆ λ„‰λ„‰ν•˜κ²Œ 생각해 미리 long long으둜 κ΅¬ν˜„ν•΄λ‘μž!


Categories:

Updated: