Problem Solving/[ν•­ν•΄99] TIL

99클럽 μ½”ν…Œ μŠ€ν„°λ”” 27일차 TIL / DP(λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°)

geum 2024. 11. 23. 19:50

✏️ 문제

[λ°±μ€€/BOJ] 11722번: κ°€μž₯ κΈ΄ κ°μ†Œν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄(https://www.acmicpc.net/problem/11722)

 

μˆ˜μ—΄ Aκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, κ°€μž₯ κΈ΄ κ°μ†Œν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄μ„ κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

예λ₯Ό λ“€μ–΄, μˆ˜μ—΄ A = {10, 30, 10, 20, 20, 10} 인 κ²½μš°μ— κ°€μž₯ κΈ΄ κ°μ†Œν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄μ€ A = {10, 30, 10, 20, 20, 10}  이고, κΈΈμ΄λŠ” 3이닀.

 

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

 

🧐 λ‚œμ΄λ„/μ†Œμš” μ‹œκ°„

βœ… λ‚œμ΄λ„: solved.ac κΈ°μ€€ S2

βœ… μ†Œμš” μ‹œκ°„: μΈ‘μ • X

βœ… ꢌμž₯ μ‹œκ°„: 1μ‹œκ°„ 15λΆ„

 

πŸ’‘ 풀이

1) 문제 이해

μ„€λͺ…κ³Ό μ˜ˆμ‹œκ°€ μ•„μ£Ό κΉ”λ”ν•˜λ‹€.

 

μˆ˜μ—΄ Aκ°€ μž…λ ₯으둜 듀어왔을 λ•Œ 'κ°€μž₯ κΈ΄ κ°μ†Œν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄'을 찾으면 λ˜λŠ”λ°, μ£Όμ˜ν•  점은 μˆ˜μ—΄μ„ μ΄λ£¨λŠ” μˆ«μžκ°€ μ—°μ†λ˜μ§€ μ•Šμ„μˆ˜λ„ μžˆλ‹€λŠ” 것이닀. 마침 λ¬Έμ œμ—μ„œ 보여쀀 μ˜ˆμ‹œκ°€ 이 κ²½μš°μ— ν•΄λ‹Ήν•œλ‹€.

 

2) 아이디어 흐름 및 μ½”λ“œ

β‘  DP ν…Œμ΄λΈ” μ •μ˜ 및 μ΄ˆκΈ°κ°’ μ±„μš°κΈ°

문제λ₯Ό 보자마자 'DP ν…Œμ΄λΈ”μ˜ i번째 μš”μ†Œ = μˆ˜μ—΄ A의 i번째 μš”μ†ŒκΉŒμ§€ 왔을 λ•Œ κ°€μž₯ κΈ΄ κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄μ˜ 길이'둜 dp ν…Œμ΄λΈ”μ„ μ •μ˜ν•΄μ•Όκ² λ‹€λŠ” 생각이 λ“€μ—ˆλ‹€. 이 뢀뢄은 λ‚˜λ¦„ 잘 μΊμΉ˜ν•œ 것 κ°™λ‹€!

 

dp ν…Œμ΄λΈ”μ˜ μ΄ˆκΈ°κ°’μ€ λͺ¨λ‘ 0으둜 두고 μˆ˜μ—΄ A의 첫 번째 μš”μ†Œλ₯Ό μ˜λ―Έν•˜λŠ” dp[0]만 1둜 μ…‹νŒ…ν•΄μ£Όμ—ˆλ‹€.

 

β‘‘ μ ν™”식 μœ λ„

점화식 μœ λ„ 단계가 쑰금 쉽지 μ•Šμ•˜λ‹€. μ˜ˆμ œλ„ 잘 ν†΅κ³Όν•΄μ„œ μ™„λ²½ν•œ 정닡이라고 μƒκ°ν–ˆλŠ”λ° ν‹€λ ΈμŠ΅λ‹ˆλ‹€λ₯Ό 받은 아이디어와 μ˜€λ‹΅ μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™λ‹€.

 

❌ μ˜€λ‹΅ μ½”λ“œ

for i in range(1, N):
    if A[i-1] > A[i]:
        dp[i] = dp[i-1]+1
    else:
        dp[i] = dp[i-1]

print(dp[N-1])

 

  • for  i in range(1, N)
    • dp ν…Œμ΄λΈ”μ—μ„œ μˆ˜μ—΄ A의 첫 번째 μš”μ†Œμ— ν•΄λ‹Ήν•˜λŠ” 값은 μ±„μ›Œμ€¬κΈ° λ•Œλ¬Έμ— λ‹€μŒ μš”μ†ŒλΆ€ν„° dp ν…Œμ΄λΈ”μ„ ν•˜λ‚˜μ”© μ±„μš°κΈ° μœ„ν•΄ 1λΆ€ν„° N-1κΉŒμ§€ λ°˜λ³΅λ¬Έμ„ λŒλ¦°λ‹€.
  • dp[i] = dp[i-1]+1
    • ν˜„μž¬ 확인 쀑인 μˆ˜μ—΄ A의 i번째 값에 λŒ€ν•΄ 이전 값이 ν˜„μž¬ 값보닀 크면 κ°μ†Œν•˜λŠ” ꡬ간이기 λ•Œλ¬Έμ— ν˜„μž¬κΉŒμ§€μ˜ κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄ 길이λ₯Ό 1 μ¦κ°€μ‹œν‚¨λ‹€.
  • print(dp[N-1])
    • dp ν…Œμ΄λΈ”μ΄ 잘 μ±„μ›Œμ‘Œλ‹€λŠ” κ°€μ • ν•˜μ— dp ν…Œμ΄λΈ”μ˜ λ§ˆμ§€λ§‰ 값이 닡이 λœλ‹€.

 

λ‚˜λ¦„ λ‘œμ§μ„ 잘 κ°–μΆ˜ 아이디어라고 μƒκ°ν–ˆλŠ”λ° λ„ˆλ¬΄ 금방 μ»· λ‹Ήν•΄μ„œ 뭐가 λ¬Έμ œμΌμ§€ 생각해봀닀.

 

βœ… μ˜€λ‹΅ 원인 뢄석

  • 잘λͺ» μœ λ„ν•œ 점화식
    • A: 4 5 4 5 4 5 → 5-4 ꡬ간이 κ°€μž₯ κΈ΄ κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄μ΄λ―€λ‘œ 정닡은 2κ°€ λ˜μ–΄μ•Ό ν•œλ‹€.
    • ν•˜μ§€λ§Œ λ‚΄ λ‘œμ§λŒ€λ‘œλΌλ©΄ dp ν…Œμ΄λΈ”μ€ [1, 1, 2, 2, 3, 3]이 λ˜μ–΄ μ •λ‹΅μœΌλ‘œ 3을 좜λ ₯ν•˜κ²Œ λœλ‹€.
    • 이 λ°˜λ‘€λ₯Ό 톡해 dp[i]λ₯Ό μ±„μš°κΈ° μœ„ν•΄ 직전 κ°’λ§Œμ„ ν™œμš©ν•˜λŠ” 게 λ¬Έμ œμž„μ„ κΉ¨λ‹«κ²Œ λ˜μ—ˆλ‹€.
  • 잘λͺ»λœ μ΄ˆκΈ°κ°’ μ„€μ •
    • dp ν…Œμ΄λΈ”μ˜ μ΄ˆκΈ°κ°’μ€ λͺ¨λ‘ 0μ΄μ—ˆλ‹€.
    • [3, 3, 3, 3, 3]처럼 증가/κ°μ†Œκ°€ μ „ν˜€ μΌμ–΄λ‚˜μ§€ μ•ŠλŠ” μƒνƒœμ˜ μˆ˜μ—΄μ΄ μž…λ ₯으둜 λ“€μ–΄μ˜¨ 경우λ₯Ό κ°„κ³Όν•˜κ³  μžˆμ—ˆλ‹€.
    • μˆ˜μ—΄μ„ 이루고 μžˆλŠ” 숫자 ν•˜λ‚˜ν•˜λ‚˜λ„ 길이 1의 λΆ€λΆ„ μˆ˜μ—΄μ— ν•΄λ‹Ήν•˜κΈ° λ•Œλ¬Έμ— λͺ¨λ“  인덱슀의 μ΄ˆκΈ°κ°’μ€ 1이 λ˜μ–΄μ•Ό ν•œλ‹€.

 

β‘’ μ ν™”식 및 dp ν…Œμ΄λΈ” μ΄ˆκΈ°κ°’ μˆ˜μ •

DP ν…Œμ΄λΈ” μ •μ˜λŠ” μ œλŒ€λ‘œ 됐닀고 νŒλ‹¨ν–ˆκΈ° λ•Œλ¬Έμ— μ–΄λ–€ 뢀뢄을 λ†“μΉ˜κ³  있던 건지 κ³ λ―Όν•˜λ‹€κ°€, μ±—μ§€ν”Όν‹°ν•œν…Œ μ•½κ°„μ˜ 힌트λ₯Ό λ°›μ•˜λ‹€.

dp[i]λ₯Ό μ±„μš°κΈ° μœ„ν•΄μ„œλŠ” μˆ˜μ—΄ A의 i번째 μš”μ†Œλ₯Ό λ§ˆμ§€λ§‰μœΌλ‘œ ν•˜λŠ” λͺ¨λ“  λΆ€λΆ„ μˆ˜μ—΄μ„ 확인해야 ν•œλ‹€.

 

이 말이 무슨 말인가 ν•˜λ©΄ λ‚΄κ°€ μ²˜μŒμ— κ΅¬μƒν–ˆλ˜ κ²ƒμ²˜λŸΌ 직전 κ°’λ§Œ 보고 dp ν…Œμ΄λΈ”μ„ μ±„μ›Œλ‚˜κ°€λŠ” 게 μ•„λ‹ˆλΌ, λΆ€λΆ„ μˆ˜μ—΄μ˜ 길이λ₯Ό λŠ˜λ €κ°€λ©΄μ„œ dp ν…Œμ΄λΈ”μ„ μ±„μš΄λ‹€λŠ” λœ»μ΄λ‹€.

 

i = 1, j = 0 → [10, 30, 10, 20, 20, 10] / 10을 λ§ˆμ§€λ§‰ μ›μ†Œλ‘œ κ°–λŠ” λΆ€λΆ„ μˆ˜μ—΄ 쀑 κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄μ˜ μ΅œλŒ€ κΈΈμ΄λŠ” 1(자기 μžμ‹ )

 

i = 2, j = 0 → [10, 30, 10, 20, 20, 10] / 30을 λ§ˆμ§€λ§‰ μ›μ†Œλ‘œ κ°–λŠ” λΆ€λΆ„ μˆ˜μ—΄ 쀑 κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄μ˜ μ΅œλŒ€ κΈΈμ΄λŠ” 1(자기 μžμ‹ )

i = 2, j = 1 → [1030, 10, 20, 20, 10] / 10을 λ§ˆμ§€λ§‰ μ›μ†Œλ‘œ κ°–λŠ” λΆ€λΆ„ μˆ˜μ—΄ 쀑 κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄μ˜ μ΅œλŒ€ κΈΈμ΄λŠ” 2

 

μœ„ 과정을 λ°˜λ³΅ν•˜λ©΄μ„œ dp ν…Œμ΄λΈ”μ˜ 값이 κ°±μ‹ λ˜λŠ”λ° 이 과정은 dp[i] = max(dp[i], dp[j]+1)μ΄λΌλŠ” μ‹μœΌλ‘œ λ‚˜νƒ€λ‚Ό 수 μžˆλ‹€.

 

3) 전체 μ½”λ“œ

N = int(input())

A = list(map(int, input().split()))

# DP[i]: A[i]λ₯Ό λ§ˆμ§€λ§‰ μ›μ†Œλ‘œ κ°–λŠ” κ°€μž₯ κΈ΄ κ°μ†Œ λΆ€λΆ„ μˆ˜μ—΄μ˜ 길이
DP = [1]*N

for i in range(1, N):
    for j in range(i):
        if A[j] > A[i]:
            DP[i] = max(DP[i], DP[j]+1)
        
print(max(DP))

 

4) μ–΄λ €μ› λ˜ 점/배운 점

🚨 μ–΄λ €μ› λ˜ 점

  • 점화식 κ΅¬ν˜„μ— 이쀑 for문이 ν•„μš”ν–ˆλ˜ 적은 처음이라 이쀑 forλ¬Έ μ“Έ 생각을 λͺ»ν•˜κ³  λ³΅μž‘ν•œ λ°©λ²•μœΌλ‘œ 풀이λ₯Ό κ³ λ―Όν•˜κ³  μžˆμ—ˆλ‹€.

❗ 배운 점

  • DP μœ ν˜•μ€ 점화식 μœ λ„κ°€ 생λͺ…이라 머리λ₯Ό 더 λ§λž‘ν•˜κ²Œ λ§Œλ“€μ–΄μ€„ ν•„μš”κ°€ μžˆλ‹€.