Problem Solving/BOJ & Programmers

[BOJ] 1463번: 1둜 λ§Œλ“€κΈ°

geum 2024. 9. 3. 18:47

✏️ 문제

μ •μˆ˜ X에 μ‚¬μš©ν•  수 μžˆλŠ” 연산은 λ‹€μŒκ³Ό 같이 μ„Έ 가지 이닀.

 

  1. Xκ°€ 3으둜 λ‚˜λˆ„μ–΄ 떨어지면, 3으둜 λ‚˜λˆˆλ‹€.
  2. Xκ°€ 2둜 λ‚˜λˆ„μ–΄ 떨어지면, 2둜 λ‚˜λˆˆλ‹€.
  3. 1을 λΊ€λ‹€.

 

μ •μˆ˜ N이 μ£Όμ–΄μ‘Œμ„ λ•Œ, μœ„μ™€ 같은 μ—°μ‚° μ„Έ 개λ₯Ό 적절히 μ‚¬μš©ν•΄μ„œ 1을 λ§Œλ“€λ €κ³  ν•œλ‹€. 연산을 μ‚¬μš©ν•˜λŠ” 횟수의 μ΅œμ†Ÿκ°’μ„ 좜λ ₯ν•˜μ‹œμ˜€.

 

πŸ€– μž…μΆœλ ₯ μ˜ˆμ‹œ

 

πŸ’‘ν’€μ΄

정말 유λͺ…ν•œ DP 문제 쀑 ν•˜λ‚˜λ‘œ, μ†”μ§νžˆ λ§ν•΄μ„œ 문제λ₯Ό λ³Έ 적은 λ§Žμ€λ° μ˜€λŠ˜μ„ ν¬ν•¨ν•˜μ—¬ 자λ ₯으둜 ν‘Ό 적은 μ—†λ‹€. μ°Έ λΆ€λ„λŸ¬μš΄ 일이야~

 

μ˜€λŠ˜μ„ DP κ³΅λΆ€μ˜ λ‚ λ‘œ μ •ν–ˆκΈ° λ•Œλ¬Έμ— μ•„μ£Ό μ„Έμ„Έν•˜κ²Œ μ½”λ“œλ₯Ό 정리해보렀고 ν•œλ‹€.

 

1) μ ‘κ·Ό 방법

1. DP ν…Œμ΄λΈ” μ •μ˜

  • 1차원 λ°°μ—΄ ν˜•νƒœμ˜ DP ν…Œμ΄λΈ” dp[i]μ—λŠ” iλ₯Ό 1둜 λ§Œλ“€κΈ° μœ„ν•΄ ν•„μš”ν•œ μ΅œμ†Œ μ—°μ‚° 횟수 μ €μž₯
  • 예) dp[3] = 1 (i=3이고 3으둜 λ‚˜λˆ„λŠ” μ—°μ‚° ν•œ 번이면 1이 됨)

2. μ΄ˆκΈ°κ°’ μ„€μ •

  • dp[1] = 0
  • μ²˜μŒμ— 문제 ν’€ λ•Œ dp[1], dp[2], dp[3] 값을 λ‹€ μ£Όκ³  μ‹œμž‘ν–ˆλŠ”λ° dp[2], dp[3]은 dp[1]만 μ•Œλ©΄ for문으둜 μ²˜λ¦¬κ°€ λΌμ„œ ꡳ이 μ΄ˆκΈ°κ°’μ„ 쀄 ν•„μš”λŠ” μ—†μ—ˆμŒ

3. ⭐ 점화식 μ„€μ • ⭐

  • β‘  dp[i-1]+1 β‘‘ dp[i//2]+1 β‘’ dp[i//3]+1 이 μ„Έ 가지 경우 쀑 μ΅œμ†Œκ°’μ΄ dp[i]에 μ €μž₯됨

 

2) μ˜ˆμ‹œ

점화식 μ„€μ • 단계 μ € ν•œ 쀄을 μ΄ν•΄ν•˜λŠ” 데에 λ„ˆλ¬΄λ‚˜ 였래 κ±Έλ € 버린 λ‚˜μ˜ λ‘λ‡Œ,, μ±—μ§€ν”Όν‹°λ‹˜κ»˜μ„œ 친절히 μž‘μ„±ν•΄μ€€ μ˜ˆμ‹œλŠ” μ•„λž˜μ™€ κ°™λ‹€.

β‘  dp[i-1]+1

iκ°€ 2와 3 κ·Έ μ–΄λŠ κ²ƒμœΌλ‘œλ„ λ‚˜λˆ„μ–΄ 떨어지지 μ•ŠλŠ” 수라고 κ°€μ •ν•΄λ³΄μž. 즉, `i=5`라고 ν–ˆμ„ λ•Œ `dp[5]=dp[4]+1`이라고 ν•  수 μžˆλŠ”λ° 쑰금 더 ν’€μ–΄ μ“°λ©΄ `dp[5] = dp[4](4λ₯Ό 1둜 λ§Œλ“€κΈ° μœ„ν•΄ ν•„μš”ν•œ μ—°μ‚° 횟수)+1(5μ—μ„œ 1을 λΊ€ ν›„ 4둜 κ°€λŠ” μ—°μ‚° 횟수)`이닀.

β‘‘ dp[i//2]+1

iκ°€ 2둜 λ‚˜λˆ„μ–΄μ§€λŠ” 경우인 `i=8`을 μƒκ°ν•΄λ³΄μž. μ΄λŸ¬ν•œ κ²½μš°μ—λŠ” `dp[8] = dp[4](4λ₯Ό 1둜 λ§Œλ“€κΈ° μœ„ν•΄ ν•„μš”ν•œ μ—°μ‚° 횟수)+1(8μ—μ„œ 2λ₯Ό λ‚˜λˆ  4둜 κ°€λŠ” μ—°μ‚° 횟수)`μ΄λΌλŠ” 식이 μ„±λ¦½ν•˜κ²Œ λœλ‹€.

 

dp[i//3]+1도 μœ„μ˜ 두 방식과 λ™μΌν•˜κΈ° λ•Œλ¬Έμ— μƒλž΅!

 

3) μ½”λ“œ

import sys

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

dp = [0]*(N+1)

for i in range(2, N+1):
    dp[i] = dp[i-1]+1
    
    # iκ°€ 2둜 λ‚˜λˆ  λ–¨μ–΄μ§€λŠ” 경우
    if i%2 == 0:
        dp[i] = min(dp[i], dp[i//2]+1)
    
    # iκ°€ 3으둜 λ‚˜λˆ  λ–¨μ–΄μ§€λŠ” 경우
    if i%3 == 0:
        dp[i] = min(dp[i], dp[i//3]+1)
    
print(dp[N])

 

점화식 μ„€μ • 단계 말고 μ½”λ“œ κ΅¬ν˜„ λ‹¨κ³„μ—μ„œλ„ ν•˜λ‚˜ 발λͺ© μž‘ν˜”λ˜ 뢀뢄이 μžˆλŠ”λ° 'μ™œ dp[i] = dp[i-1]+1κ°€ λ¨Όμ € λ‚˜μ˜€μ§€?'λ₯Ό 이해 λͺ» ν–ˆμ—ˆλ‹€.

 

근데 μ–΄λ €μš΄ 뢀뢄은 μ•„λ‹ˆμ—ˆκ³  κ·Έλƒ₯ 'β‘  dp[i-1]+1 β‘‘ dp[i//2]+1 β‘’ dp[i//3]+1 이 μ„Έ 가지 경우 쀑 μ΅œμ†Œκ°’'을 κ΅¬ν•˜κΈ° μœ„ν•΄ 1을 λΉΌλŠ” κ³Όμ •μ˜ 값을 미리 μ €μž₯ν•΄λ‘λŠ” κ±°μ˜€λ‹€. 1을 λΉΌλŠ” 과정은 2둜 λ‚˜λˆ μ§€κ±°λ‚˜ 3으둜 λ‚˜λˆ μ§€λŠ” κ±Έ μƒκ°ν•˜μ§€ μ•Šκ³  λͺ¨λ“  값에 κ³΅ν†΅μœΌλ‘œ 적용될 수 μžˆλŠ” 것이기 λ•Œλ¬Έμ— κ°€μž₯ λ¨Όμ € μ²˜λ¦¬ν•΄μ£ΌλŠ” κ²ƒμ΄μ—ˆμŒ

 

πŸ€“ μ°Έκ³ 

생각도 λͺ»ν–ˆλŠ”데 풀이 μ’€ 찾아보닀 λ³΄λ‹ˆκΉŒ 이 λ¬Έμ œλŠ” κ²°κ΅­ μ΅œμ†Ÿκ°’μ„ κ΅¬ν•˜λŠ” 거라 BFS둜 ν‘Ό 뢄듀도 κ½€ λ§Žμ•˜λ‹€. 그리고 이 λ¬Έμ œλŠ” BFS둜 μ½”λ“œ μ œμΆœν•˜λ‹ˆκΉŒ DP 방식보닀 μˆ˜ν–‰ 속도가 훨씬 λΉ¨λΌμ„œ μ±„μ°ν”Όν‹°ν•œν…Œ 이유λ₯Ό λ¬Όμ–΄λ΄€λŠ”λ° μ„€λͺ…을 μš”μ•½ν•˜μžλ©΄

 

"DPλŠ” λͺ¨λ“  μˆ˜μ— λŒ€ν•΄ 연산을 μ§„ν–‰ν•˜μ§€λ§Œ BFSλŠ” 주어진 1둜 λ„λ‹¬ν•˜κΈ°κΉŒμ§€ ν•„μš”ν•œ μˆ˜μ— λŒ€ν•΄μ„œλ§Œ 연산을 진행"

 

ν•˜κΈ° λ•Œλ¬Έμ— BFSκ°€ 더 빠름 μ΄μ—ˆλ‹€. BFS κ΅¬ν˜„ μ½”λ“œλŠ” μ•„λž˜μ— ν•¨κ»˜ λ„£μ–΄λ‘”λ‹€.

 

import sys

from collections import deque

def bfs_min_operations(n):
    queue = deque([(n, 0)])  # (ν˜„μž¬ 숫자, μ—°μ‚° 횟수)
    visited = set()  # λ°©λ¬Έν•œ μˆ«μžλ“€μ„ μ €μž₯
    visited.add(n)
    
    while queue:
        current, operations = queue.popleft()
        
        # ν˜„μž¬ μˆ«μžκ°€ 1이라면, μ—°μ‚° 횟수λ₯Ό λ°˜ν™˜
        if current == 1:
            return operations
        
        # 1을 λΉΌλŠ” 경우
        if current - 1 > 0 and current - 1 not in visited:
            queue.append((current - 1, operations + 1))
            visited.add(current - 1)
        
        # 2둜 λ‚˜λˆ„λŠ” 경우
        if current % 2 == 0 and current // 2 not in visited:
            queue.append((current // 2, operations + 1))
            visited.add(current // 2)
        
        # 3으둜 λ‚˜λˆ„λŠ” 경우
        if current % 3 == 0 and current // 3 not in visited:
            queue.append((current // 3, operations + 1))
            visited.add(current // 3)

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

print(bfs_min_operations(N))

 

μ•„ DP μž˜ν•˜κ³  싢어라 ~

'Problem Solving > BOJ & Programmers' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[BOJ] 7568번: 덩치  (0) 2024.09.09
[BOJ] 9095번: 1, 2, 3 λ”ν•˜κΈ°  (0) 2024.09.03
[BOJ] 11399번: ATM  (0) 2024.08.27
[BOJ] 2839번: 섀탕 배달  (1) 2024.08.27
[BOJ] 2217번: λ‘œν”„  (1) 2024.02.25