일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 영어원서읽기
- 쓰릴오브파이트
- 링피트
- 30분
- realclass
- 프로젝트
- 운동
- 잡생각
- Writing
- 개발자
- 미드시청
- 괜찮음
- 뭐든
- 화상영어
- 월간
- 스탭퍼
- 영어공부
- Problem Solving
- Daily Challenge
- FIT XR
- 10분
- 읽기
- 매일
- 만화도
- English
- 파비최
- 사이드
- leetcode
- 리얼 클래스
- 3줄정리
- Today
- Total
파비의 매일매일 공부기록
5.8 철근 자르기 - DP 본문
지난 시간의 소스와 거의 동일한 형태다.
다만, 더 이상 재귀 호출은 사용하지 않고 반복문으로 끝냄.
2중 for문 사용으로 시간 복잡도는 최대 O(n^2)가 됨.
def solve_dp(v, n):
cache = [0 for _ in range(n+1)]
for i in range(1, n + 1):
cache[i] = -987654321
for j in range(1, i + 1):
cache[i] = max(cache[i], v[j] + cache[i - j]) # 핵심 line
return cache[n]
if __name__ == '__main__':
v = [0] + list(map(int, input().split()))
print(solve_dp(v, len(v) - 1))
v가 2, 3, 6, 7 일 때를 기준으로 소스를 분석해보면 다음과 같다.
cache [1]의 초기값은 -987654321
그다음 반복문을 거치면
cache [1] = max(-987654321, 2 + 0) = 2 가 된다.
cache [2]의 초기값도 -987654321
그다음 반복문을 거치면
cache [2] = max(-987654321, 2 + 2) = 4
cache [2] = max(4, 3 + 0) = 4
결국 1짜리 막대기 두 개의 값 와 2짜리 막대기 한 개의 값을 비교해서 구하는 것과 동일하다.
cache [3]의 초기값도 -987654321
그다음 반복문을 거치면
cache [3] = max(-987654321, 2 + 4) = 6
cache [3] = max(6, 2 + 3) = 6
cache [3] = max(6, 6 + 0) = 6
이것도 결국은 2짜리 막대기를 구하는데 최댓값 + 1짜리 막대기 혹은 3짜리 막대기 1개 중 최댓값을 구하는 것과 동일하다.
마지막으로 cache [4]의 초기값 역시 -987654321
그다음 반복문을 거치면
cache [4] = max(-987654321, 2 + 6) = 8
cache [4] = max(8, 3 + 4) = 8
cache [4] = max(8, 6 + 2) = 8
cache [4] = max(8, 8 + 0) = 8
마지막도 기존까지 구했던 막대기들의 최댓값에 부족한 길이들을 더해서 최댓값을 구하는 로직이라고 볼 수 있다.
오랜만에 잘 이해가 안 가는 부분을 디버깅해가면서 추적해보니 이해가 꽤 잘된다.
재귀의 경우 stack을 하나씩 봐야 하는 불편함이 있는데, 역시 DP는 로직 확인 하기가 훨씬 수월하다.
'Study > Algorithm 문제풀이' 카테고리의 다른 글
5.9 0-1 배낭 - DP (0) | 2021.09.22 |
---|---|
5.9 0-1 배낭 - 재귀 (0) | 2021.09.21 |
5.8 철근 자르기 - 메모전략 (0) | 2021.09.19 |
5.8 철근 자르기 - 재귀 (0) | 2021.09.18 |
5.7 거스름돈 최적화 - DP (0) | 2021.09.17 |