Algorithm/Baekjoon

[λ°±μ€€] (Python) 11055번 - κ°€μž₯ 큰 μ¦κ°€ν•˜λŠ” μˆ˜μ—΄ (dp 풀이 방법)

감자 πŸ₯” 2023. 4. 1. 17:39
λ°˜μ‘ν˜•

κΈ°μ—… μ½”λ”©ν…ŒμŠ€νŠΈ μ—°μŠ΅μœΌλ‘œ Swiftκ°€ μ•„λ‹ˆλΌ Python으둜 ν’€μ΄ν–ˆμŠ΅λ‹ˆλ‹€ πŸ˜…

 

⚫️ 문제

https://www.acmicpc.net/problem/11055

 

11055번: κ°€μž₯ 큰 μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄

μˆ˜μ—΄ Aκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, κ·Έ μˆ˜μ—΄μ˜ μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄ μ€‘μ—μ„œ 합이 κ°€μž₯ 큰 것을 κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€. 예λ₯Ό λ“€μ–΄, μˆ˜μ—΄ A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 κ²½μš°μ— 합이 κ°€μž₯ 큰 μ¦κ°€ν•˜λŠ”

www.acmicpc.net

 

⚫️ λ‚˜μ˜ 풀이

이전에 보고와야할 것이 μžˆλ‹€. 'κ°€μž₯ 큰 μ¦κ°€ν•˜λŠ” μˆ˜μ—΄'은 주어진 μˆ˜μ—΄ μ†μ—μ„œ 'μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄'을 μ°ΎλŠ” λ¬Έμ œλ‹€. LIS라고 λΆˆλ¦°λ‹€.

https://didu-story.tistory.com/236

 

[μ•Œκ³ λ¦¬μ¦˜] (Swift) μ΅œκ°• 증가 λΆ€λΆ„ μˆ˜μ—΄ (LIS) μ•Œκ³ λ¦¬μ¦˜ (DP, λ™μ κ³„νšλ²•μ„ ν™œμš©ν•œ LIS)

졜μž₯ 증가 λΆ€λΆ„ μˆ˜μ—΄ (LIS,Longest Increasing Subsequence) μ΄λž€? μ–΄λ–€ μž„μ˜μ˜ μˆ˜μ—΄μ΄ μ£Όμ–΄μ§ˆ λ•Œ, 이 μˆ˜μ—΄μ—μ„œ λͺ‡ 개의 μˆ˜λ“€μ„ μ œκ±°ν•΄μ„œ λΆ€λΆ„ μˆ˜μ—΄μ„ λ§Œλ“€ 수 μžˆλ‹€. μ΄λ•Œ λ§Œλ“€μ–΄μ§„ λΆ€λΆ„ μˆ˜μ—΄ 쀑 μ˜€λ¦„μ°¨μˆœμœΌ

didu-story.tistory.com

λ‚΄κ°€ μ΄λ ‡κ²Œ... ν¬μŠ€νŒ…λ„ 해놨닀. 

기본적으둜 LISλ₯Ό κ΅¬ν•˜λŠ” 방식은 두가지닀. '이뢄탐색'방식을 ν™œμš©ν•˜λŠ” 것과 'dp'λ₯Ό μ΄μš©ν•˜λŠ”κ²ƒ! 두 개 λͺ¨λ‘ μ˜¬λ°”λ₯Έ 풀이이긴 ν•˜μ§€λ§Œ, μ‹œκ°„λ³΅μž‘λ„μ— μ£Όμ˜ν•΄μ•Όν•œλ‹€. dpλŠ” for문을 μ΄μ€‘μœΌλ‘œ μ€‘μ²©ν•΄μ„œ λ§Œλ“€κΈ° 떄문에 O(N^2)의 μ‹œκ°„ λ³΅μž‘λ„λ₯Ό κ°–λŠ”λ‹€. λ°˜λ©΄μ—, 이뢄탐색을 μ‚¬μš©ν•˜λ©΄ O(nlogn)의 μ‹œκ°„μ„ κ°–λŠ”λ‹€. 떄문에, 주어진 N에 λŒ€ν•˜μ—¬ μ‹œκ°„λ³΅μž‘λ„λ₯Ό κ³ λ €ν•΄μ„œ 문제λ₯Ό ν’€μ–΄μ•Όν•œλ‹€.

μœ„ λ‚΄ ν¬μŠ€νŒ…μ—λŠ” dpλ₯Ό μ΄μš©ν•΄μ„œ κ΅¬ν•˜λŠ” 방식을 μ„€λͺ…ν•΄λ’€λ‹€. 그것을 기반으둜 문제λ₯Ό ν’€μ§€λ§Œ, 이번 λ¬Έμ œλŠ” 쑰금 λ‹€λ₯΄λ‹€. μ΄λ²ˆλ¬Έμ œμ—μ„œλŠ” κ°€μž₯ 큰 μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄μ˜ 길이λ₯Ό κ΅¬ν•˜λŠ”κ²Œ μ•„λ‹ˆλΌ, λΆ€λΆ„μˆ˜μ—΄λ“€ 쀑에, κ·Έ 합이 κ°€μž₯ 큰 것을 μ •λ‹΅μœΌλ‘œ κ³¨λΌμ•Όν•œλ‹€. κ·Έλ ‡λ‹€λ©΄, dp에 어떀것듀을 λ„£μ–΄μ£Όμ–΄μ•Όν• κΉŒ?

λ‚΄κ°€ μ²˜μŒμ— μƒκ°ν•œ 방식은 이거닀.

dp[i] =  arr[i]λ₯Ό κΈ°μ€€μœΌλ‘œ μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄μ˜ μ΅œλŒ€ ν•©

(μ˜ˆμ‹œ)
arr = [1, 100, 2, 50] 이라치자.
dp[0] μ—λŠ” arr[0]이 λ§ˆμ§€λ§‰ν•­μ΄ 된 Lis의 합을 λ„£λŠ”λ‹€. 즉, dp[0] = 1 μ΄λœλ‹€.
dp[1] 은, 100이고 이전 (i-1) 값보닀 ν¬λ―€λ‘œ, [1, 100]은 μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄μ΄λ‹€. κ·Έλž˜μ„œ dp[1]μ—λŠ” λ‘κ°œμ˜ 합인 101을 λ„£λŠ”λ‹€.
dp[2]λŠ” 2이닀. μ•žκ³Ό 같이 이전(i-1)κ°’κ³Ό λΉ„κ΅ν•΄λ³΄λ‹ˆ, 100이 더 ν¬λ―€λ‘œ μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄μ΄ 될 수 μ—†λ‹€. ν•˜μ§€λ§Œ, arr[i-2]번째인 1보닀 2κ°€ ν¬λ―€λ‘œ, [1,2]둜 μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄μ„ λ§Œλ“€ 수 μžˆλ‹€. 그럼 dp[2] μ—λŠ” 1κ³Ό 2λ₯Ό λ”ν•œ 3을 λ„£μ–΄μ€€λ‹€.
... (계속) πŸ”

μ΄λ ‡κ²Œ dp에 값을 넣어쀄 수 μžˆμ„ 것이닀.

μ—¬κΈ°μ„œ dp[2]λ₯Ό ꡬ할 λ•Œ, arrμ—μ„œ 0번째 λΆ€ν„° μˆœνšŒν•˜λ©΄μ„œ ν˜„μž¬μ˜ 2보닀 μž‘μ€μ§€ 봐주고, μž‘λ‹€λ©΄ 1κΉŒμ§€μ˜ ν•© (dp) + ν˜„μž¬μ˜ 2λ₯Ό λ”ν•΄μ£ΌλŠ” μ‹μœΌλ‘œ κ°€λ©΄ λœλ‹€.  이해가 νž˜λ“€λ‹€λ©΄ μ•„λž˜ 그림을 보자.

 

μœ„μ—μ„œ 말둜 μ„€λͺ…ν•΄λ‘” 것을 μ΄λ ‡κ²Œ κ·Έλ¦¬λ©΄μ„œ μƒκ°ν–ˆλ‹€. λ§ˆμ§€λ§‰ i=2 κ°€ λ˜μ—ˆμ„λ•Œ, 쑰건과 이쀑 for문을 생각해낼 수 μžˆμ—ˆλ‹€.

 

⚫️ μ •λ‹΅ μ½”λ“œ

n = int(input())
arr = list(map(int, input().split()))
dp = [0] * n

dp[0] = arr[0]

for i in range(0, n):
    dp[i] = arr[i]
    for j in range(0, i):
        if arr[j] < arr[i] and dp[i] < dp[j] + arr[i]:
            dp[i] = max(dp[i], dp[j]+arr[i])

print(max(dp))
λ°˜μ‘ν˜•