πŸ“š Study/Algorithm

[Algorithm] λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°

윰갱 2025. 3. 4. 16:57

μ€‘λ³΅λ˜λŠ” 연산을 μ€„μ΄μž

μ»΄ν“¨ν„°λŠ” μ—°μ‚° 속도에 ν•œκ³„κ°€ 있고, λ©”λͺ¨λ¦¬ 곡간을 μ‚¬μš©ν•  수 μžˆλŠ” 데이터 κ°œμˆ˜λ„ ν•œμ •μ μ΄λ‹€.

λ”°λΌμ„œ μš°λ¦¬λŠ” μ—°μ‚° 속도와 λ©”λͺ¨λ¦¬ 곡간을 μ΅œλŒ€ν•œ ν™œμš©ν•  수 μžˆλŠ” 효율적인 μ•Œκ³ λ¦¬μ¦˜μ΄ ν•„μˆ˜μ μ΄λ‹€.

ν”„λ‘œκ·Έλž˜λ°μ—μ„œ 'λ‹€μ΄λ‚˜λ―Ή'μ΄λž€, 'ν”„λ‘œκ·Έλž¨μ΄ μ‹€ν–‰λ˜λŠ” 도쀑에'λΌλŠ” μ˜λ―Έμ΄λ‹€. (ex. 동적할당)
κ·ΈλŸ¬λ‚˜ λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ€ 이와 관련이 μ—†λ‹€.

 


# μ˜ˆμ‹œ

λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μœΌλ‘œ ν•΄κ²°ν•  수 μžˆλŠ” λŒ€ν‘œμ μΈ μ˜ˆμ‹œλ‘œ ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ΄ μžˆλ‹€.

 

$$a_n = a_{n-1} + a_{n-2}, a_1 = 1, a_2 = 1$$

 

그럼, μ½”λ“œλ‘œλŠ” μ–΄λ–»κ²Œ κ΅¬ν˜„ν•  수 μžˆμ„κΉŒ?

κ°€μž₯ μ‰½κ²Œ 생각할 수 μžˆλŠ” 방법은 λ°”λ‘œ μž¬κ·€ν•¨μˆ˜μΌ 것이닀.

 

 

κ·ΈλŸ¬λ‚˜ μ½”λ“œλ₯Ό 이와 같이 짜면 μ‹¬κ°ν•œ λ¬Έμ œκ°€ 생긴닀.

λ°”λ‘œ n이 컀지면 컀질수둝 μˆ˜ν–‰μ‹œκ°„μ΄ κΈ°ν•˜κΈ‰μˆ˜μ μœΌλ‘œ μ¦κ°€ν•˜λŠ” 것이닀.

이 μ½”λ“œμ˜ μ‹œκ°„ λ³΅μž‘λ„λŠ” $$O(2^N)$$이기 λ•Œλ¬Έμ΄λ‹€.

$$N=30$$이면, μ•½ 10μ–΅ κ°€λŸ‰μ˜ 연산을 μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€λ©΄ λ”μš± 감이 작힐 것이닀.

 

$$f(6)$$일 λ•Œμ˜ 호좜 과정은 μ•„λž˜μ™€ 같이 μ‹œκ°ν™”ν•  수 μžˆλŠ”λ°,

μ΄λ•Œ μžμ„Ένžˆ 보면 λ™μΌν•œ ν•¨μˆ˜κ°€ 반볡적으둜 ν˜ΈμΆœλ˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

 

$$f(6)$$을 ν˜ΈμΆœν•˜λŠ”λ° $$f(3)$$은 무렀 3λ²ˆμ΄λ‚˜ 호좜된 것이닀.

이처럼 ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ„ μž¬κ·€ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄ λ§Œλ“€ μˆ˜λŠ” μžˆμ§€λ§Œ,

λ‹¨μˆœνžˆ 맀번 κ³„μ‚°ν•˜λ„λ‘ ν•˜λŠ”κ±΄ 문제λ₯Ό 효율적으둜 ν’€μ§€ λͺ»ν•œλ‹€.

 

λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ„ μ‚¬μš©ν•˜λ©΄ 효율적으둜 μ²˜λ¦¬ν•  수 μžˆλŠ”λ°

이 ν”„λ‘œκ·Έλž˜λ°μ„ 항상 μ‚¬μš©ν•  수 μžˆλŠ” 것은 μ•„λ‹ˆλ‹€. μ•„λž˜ 두 κ°€μ§€ 쑰건이 μ •μ˜λ˜μ–΄μ•Ό ν•œλ‹€.

[μ „μ œ]

1. 큰 문제λ₯Ό μž‘μ€ 문제둜 λ‚˜λˆŒ 수 μžˆλ‹€.
2. μž‘μ€ λ¬Έμ œμ—μ„œ κ΅¬ν•œ 정닡은 그것을 ν¬ν•¨ν•˜λŠ” 큰 λ¬Έμ œμ—μ„œλ„ λ™μΌν•˜λ‹€

 

ν”Όλ³΄λ‚˜μΉ˜ 문제λ₯Ό μž¬κ·€ν•¨μˆ˜κ°€ μ•„λ‹Œ, λ©”λͺ¨μ΄μ œμ΄μ…˜(Memoization) 기법을 μ‚¬μš©ν•˜μ—¬ ν•΄κ²°ν•΄λ³΄μž!

λ©”λͺ¨μ΄μ œμ΄μ…˜(Memoization) = 캐싱(Caching)
: λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ° 기법 쀑 ν•˜λ‚˜λ‘œ
  ν•œλ²ˆ κ΅¬ν•œ κ²°κ³Όλ₯Ό λ©”λͺ¨λ¦¬ 곡간에 λ©”λͺ¨ν•΄λ‘κ³  같은 식을 λ‹€μ‹œ ν˜ΈμΆœν•˜λ©΄
  λ©”λͺ¨ν•œ κ²°κ³Όλ₯Ό κ·ΈλŒ€λ‘œ κ°€μ Έμ˜€λŠ” 기법

κ΅¬ν˜„ 방법
: ν•œ 번 κ΅¬ν•œ 정보λ₯Ό λ¦¬μŠ€νŠΈμ— μ €μž₯
: μž¬κ·€μ μœΌλ‘œ μˆ˜ν–‰ν•˜λ‹€κ°€ 같은 정보가 ν•„μš”ν•  λ•Œ 정닡을 κ·ΈλŒ€λ‘œ λ¦¬μŠ€νŠΈμ—μ„œ κ°€μ Έμ˜€λ©΄ 됨

 

μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

$$d$$ λ¦¬μŠ€νŠΈμ—λŠ” ν•œ 번 κ΅¬ν•œ 정보인지 μ•„λ‹Œμ§€μ— λŒ€ν•œ 정보가 λ‹΄κ²¨μžˆλŠ” 것이닀.

 

문제λ₯Ό μž‘κ²Œ λ‚˜λˆˆλ‹€κ³ ? 퀡 μ •λ ¬μ˜ λΆ„ν•  정볡 μ•Œκ³ λ¦¬μ¦˜κ³Ό λΉ„μŠ·ν•΄λ³΄μ΄λŠ”λ°?

λΉ„μŠ·ν•˜μ§€λ§Œ,
퀡 정렬은 ν•œλ²ˆ κΈ°μ€€ μ›μ†Œ Pivotκ°€ 자리λ₯Ό λ³€κ²½ν•΄μ„œ 자리λ₯Ό 작게 되면
κ·Έ κΈ°μ€€ μ›μ†Œμ˜ μœ„μΉ˜λŠ” 더 이상 λ°”λ€Œμ§€ μ•Šκ³  κ·Έ 피벗값을 λ‹€μ‹œ μ²˜λ¦¬ν•˜λŠ” λΆ€λΆ„ λ¬Έμ œλŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.
그에 λ°˜ν•΄ λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ€ ν•œλ²ˆ ν•΄κ²°ν–ˆλ˜ 문제λ₯Ό λ‹€μ‹œκΈˆ ν•΄κ²°ν•œλ‹€.

 

 

 

λ©”λͺ¨μ΄μ œμ΄μ…˜ 방법을 μ‚¬μš©ν•œ μ•Œκ³ λ¦¬μ¦˜μ„ μ‹œκ°ν™”ν•΄λ³΄λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

$$f(6)$$을 ν˜ΈμΆœν•  λ•Œ, μ΄μ œλŠ” μ•„λž˜μ²˜λŸΌ 훨씬 호좜 νšŸμˆ˜κ°€ μ€„μ—ˆλ‹€.

λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ— μ˜ν•΄ ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄ μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹œκ°„ λ³΅μž‘λ„λŠ” $$O(N)$$으둜 μ€„μ—ˆλ‹€.

 

이처럼 μž¬κ·€ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ° μ†ŒμŠ€μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 방법을,

큰 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ μž‘μ€ 문제λ₯Ό ν˜ΈμΆœν•œλ‹€κ³  ν•˜μ—¬ νƒ‘λ‹€μš΄Top-Down = 상ν–₯식 λ°©μ‹μ΄λΌκ³  λ§ν•œλ‹€.

λ°˜λ©΄μ—, λ‹¨μˆœνžˆ λ°˜λ³΅λ¬Έμ„ μ΄μš©ν•˜μ—¬ μ†ŒμŠ€μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 경우

μž‘μ€ λ¬Έμ œλΆ€ν„° μ°¨κ·Όμ°¨κ·Ό 닡을 λ„μΆœν•œλ‹€κ³  ν•˜μ—¬ 보텀업Botton-Up = ν•˜ν–₯식 방식이라고 ν•œλ‹€. 

 

보텀업Bottom-Up 방법을 μ‚¬μš©ν•΄μ„œ ν•΄κ²°ν•œ μ½”λ“œλŠ” 이와 κ°™λ‹€. 훨씬 κ°„λ‹¨ν•œ λ“―!

 

λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ˜ μ „ν˜•μ μΈ ν˜•νƒœλŠ” 보텀업Bottom-Up 방식이닀.
보텀업 λ°©μ‹μ—μ„œ μ‚¬μš©λ˜λŠ” κ²°κ³Ό μ €μž₯용 λ¦¬μŠ€νŠΈλŠ” 'DP ν…Œμ΄λΈ”'이라고 λΆ€λ₯΄κ³ ,
λ©”λͺ¨μ΄μ œμ΄μ…˜μ€ νƒ‘λ‹€μš΄ λ°©μ‹μ—μ„œ κ΅­ν•œλ˜μ–΄ μ‚¬μš©λ˜λŠ” ν‘œν˜„μ΄λ‹€.

 


# 문제 ν‘ΈλŠ” 방법

1. μ£Όμ–΄μ§„ λ¬Έμ œκ°€ λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ° μœ ν˜•μž„μ„ νŒŒμ•…ν•˜κΈ°

2. μ™„μ „ 탐색 μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ μ ‘κ·Όν–ˆμ„ λ•Œ μ‹œκ°„μ΄ 맀우 였래 걸리면 > λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ° 적용 κ°€λŠ₯ν• κΉŒ?

3. μž¬κ·€ ν•¨μˆ˜λ‘œ λΉ„νš¨μœ¨μ μΈ ν”„λ‘œκ·Έλž¨ μž‘μ„± (νƒ‘λ‹€μš΄) > μ½”λ“œ κ°œμ„  -- λ©”λͺ¨μ œμ΄μ…˜ 방법 μ‚¬μš©

4. 3번 λ³΄λ‹€λŠ” 보텀업 λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•˜λŠ” 것을 ꢌμž₯, μŠ€νƒ 크기가 ν•œμ •λ˜μ–΄ μžˆμ„ 수 있기 λ•Œλ¬Έ


# 2-1. 1둜 λ§Œλ“€κΈ°

import sys
X = int(input())

d = [0]*(X+1)

for i in range(2, X+1):
  d[i] = d[i-1] + 1
  if i%5 == 0:
    d[i] = min(d[i], d[i//5]) + 1
  elif i%3 == 0:
    d[i] = min(d[i], d[i//3]) + 1
  elif i%2 == 0:
    d[i] = min(d[i], d[i//2]) + 1

print(d[X])

ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” 과정을 그리면 μ½”λ“œλ₯Ό μ§œλŠ”κ²Œ 더 간단해진닀.

μš°λ¦¬λŠ” $$X$$κ°€ μžˆμ„ λ•Œ (λ§Œμ•½ xκ°€ 2,3,5에 λͺ¨λ‘ λ‚˜λˆ„μ–΄λ–¨μ–΄μ§„λ‹€λ©΄..)

$$f(X) = f(X-1) + 1$$

$$f(X) = f(X//2) + 1$$

$$f(X) = f(X//3) + 1$$

$$f(X) = f(X//5) + 1$$

이 쀑에 κ°€μž₯ μž‘μ€ 값을 μ·¨ν•˜κ²Œ λœλ‹€. μ ν™”μ‹μœΌλ‘œ ν‘œν˜„ν•˜λ©΄, $$a_i = min(a_{i-1}, a_{i/2},  a_{i/3},  a_{i/5})$$


# 2-2. κ°œλ―Έμ „μ‚¬

 

import sys
N = int(sys.stdin.readline().strip())
array = list(map(int,sys.stdin.readline().split()))

d = [0]*(N)
d[0] = array[0]
d[1] = max(array[0], array[1])

for i in range(2, N):
  d[i] = max(d[i-1], d[i-2]+array[i])

print(d[N-1])

 

ν˜„μž¬ μœ„μΉ˜μ—μ„œ μ–΄λ–€ μ‹λŸ‰ μ°½κ³ λ₯Ό                                                                                                                                                                   ν„Έμ§€λŠ” μ•„λž˜μ²˜λŸΌ (1) λ°”λ‘œ 직전과 (2) μ „ 전을 ν™•μΈν•˜λ©΄ λœλ‹€.

이λ₯Ό ν‘œν˜„ν•œ 점화식은 λ‹€μŒκ³Ό κ°™λ‹€. $$a_i = max(a_{i-1}, a_{i-2} + k_i)$$


# 2-3. λ°”λ‹₯ 곡사

import sys
N = int(sys.stdin.readline().strip())

d = [0]*(N+1)
d[1] = 1
d[2] = 3

for i in range(3, N+1):
  d[i] = d[i-1] + (d[i-2] * 2)

print(d[N])

점화식을 ν‘œν˜„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€ $$a_i = a_{i+1} + a_{i-2}*2$$


# 2-4. 효율적인 화폐 ꡬ성

 

import sys
N, M = map(int,sys.stdin.readline().split())

coins = [int(sys.stdin.readline().strip()) for _ in range(N)]
d = [10001]*(M+1)

d[0] = 0
for i in range(N):
  for j in range(coins[i], M+1):
    if d[j-coins[i]] != 10001:
      d[j] = min(d[j], d[j-coins[i]]+1)

if d[M] == 10001:
  print(-1)
else:
  print(d[M])

 

κΈˆμ•‘ $$i$$λ₯Ό λ§Œλ“€ 수 μžˆλŠ” μ΅œμ†Œν•œμ˜ 화폐 개수: $$a_i$$, ν™”νμ˜ λ‹¨μœ„: $$k$$

- $$a_{i-k}$$λ₯Ό λ§Œλ“œλŠ” 방법이 μ‘΄μž¬ν•˜λŠ” 경우: $$a_i = min(a_i, a_{i-k}+1)$$

- $$a_{i-k}$$λ₯Ό λ§Œλ“œλŠ” 방법이 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 경우:  $$a_i=10,001$$

예λ₯Ό λ“€μ–΄, $$N=3, K=7$$이고, 각 ν™”νμ˜ λ‹¨μœ„κ°€ $$2,3,5$$인 경우λ₯Ό μƒκ°ν•΄λ³΄μž!

 

step0: μ΄ˆκΈ°ν™”

νŠΉμ • κΈˆμ•‘μ„ λ§Œλ“€ 수 μžˆλŠ” 화폐 ꡬ성이 κ°€λŠ₯ν•˜μ§€ μ•Šλ‹€λŠ” 의미둜 = 10,001 κ°’ μ„€μ •

 

step1: 화폐 λ‹¨μœ„ 2λΆ€ν„° 점화식을 ν™•μΈν•˜κΈ° μ‹œμž‘ν•œλ‹€.

$$a_2 = a_0 + 1 = 0 + 1 = 1$$

$$a_4 = a_2 + 1 = 1 + 1 = 2 $$

$$a_6 = a_4 + 1 = 2 + 1 = 3 $$

λ‹€μŒ 점화식에 μ˜ν•΄ ν‘œλ₯Ό μ±„μ›Œ 넣을 수 μžˆλ‹€.

 

step2: κ·Έ λ‹€μŒμ€ 화폐 λ‹¨μœ„ 3을 ν™•μΈν•˜κΈ° μ‹œμž‘ν•œλ‹€.

$$a_3 = a_0 + 1 = 0 + 1 = 1$$

$$a_6 = a_3 + 1 = 1 + 1 = 2 $$ (update!)

$$a_7 = a_4 + 1 = 2 + 1 = 3 $$

λ‹€μŒ 점화식에 μ˜ν•΄ ν‘œλ₯Ό μ±„μ›Œ 넣을 수 μžˆλ‹€.

 

step3: λ§ˆμ§€λ§‰μœΌλ‘œ, ν™”폐 λ‹¨μœ„ 5을 ν™•μΈν•˜κΈ° μ‹œμž‘ν•œλ‹€.

$$a_5 = a_0 + 1 = 0 + 1 = 1$$

$$a_7 = a_2 + 1 = 1 + 1 = 2 $$ (update!)

λ‹€μŒ 점화식에 μ˜ν•΄ ν‘œλ₯Ό μ±„μ›Œ 넣을 수 μžˆλ‹€.