공부한 날짜: 2021. 11. 08
1. 동적계획법
- 제일 작은 부분 문제부터 상위에 있는 문제로 풀어올라가는 방법(Bottom up)
문제의 각 단계에 있는 부분 문제들은 그 이전 단계에 있는 문제들의 답에 의존하고, 한번 푼 적이 있는 부분 문제의 답은 테이블에 저장한다
- 부분 문제들이 겹치는가(반복 되는가)
- 최적 부분구조(문제의 정답을 작은 문제의 정답으로부터 구할 수 있는가), 부분문제 최적해의 disjoin union은 전체문제의 최적해
(1) 문제를 부분 문제로 나눈다
(2) 가장 작은 부분 문제부터 해를 구한 뒤 테이블에 저장한다
(3) 테이블에 저장되어 있는 부분 문제의 해를 이용하여 점차적으로 상위 부분 문제의 최적해를 구한다
1_2. 부분 문제들이 겹치는가: 동적계획법으로 피보나치 수 알고리즘 구현 (python)
: 한번 거쳤던 항들은 모두 memo에 저장된다. 따라서, 다음에 구할 때는 연산없이 리턴이 가능하다
1_3: 최적 부분구조 : 문제의 정답을 작은 문제의 정답으로부터 구할 수 있는가
ex) 최단경로 구하기: A에서 C로 가는 최단경로(큰 문제)= A에서 B로 가는 최단경로(작은 문제) + B에서 C로가는 최단경로(작은문제)
따라서, 정답을 한번 구했으면 Memoization하여, 반복연산을 없애는 과정이 중요하다
2. 다이나믹 프로그래밍 구현 (두 방법의 정확한 차이점을 잘 모르겠음)
Top-down : 위에서 아래로 해결한다(ex: 재귀함수)
1. 문제를 쪼갠다.(이게 bottom-up과 다른점)
2.작은 문제를 푼다.
3. 작은 문제의 정답으로 큰 문제를 해결한다.
Bottom-up : 아래에서 위로(ex: 반복문)
1. 작은 문제부터 풀어나간다.
2.문제의 크기를 점점 크게 만들어 푼다.
3. 작은 문제들을 해결했기 때문에, 한단계 위의 큰 문제를 풀 수 있다.
4. 최종적인 문제를 해결한다.
시간 복잡도는 비슷한 수준이며, 문제에 따라 구현하기 편한것을 선택하여 풀면된다(즉, 어떤것으로 풀어도 큰 상관은 없다)
다만 파이썬 같은 경우는 재귀로 풀게되면 메모리초과가 날 가능성이 타 언어보다 높기 때문에, 반복문(bottom-up)으로 푸는게 낫다고 한다
-문제를 해결할때
- 점화식을 정의한다
- 문제를 어떤식으로 쪼갤지(작게 만들지) 생각한다
- 작은 문제의 답을 통해 어떻게 최종적인 문제를 해결할 수 있을지 생각한다
예를 들어 카드를 i개 구매하는 문제라고하면, 하나 구매할때, 두개구매할때, 차근차근 생각해보고, 적어보면 규칙이 보이거나 점화식이 보인다. 비슷한 유형을 풀어보며 감을 기르는게 무엇보다 중요한 것 같다.
출처: https://infinitt.tistory.com/246
알고리즘 - 다이나믹 프로그래밍 (Dynamic Programming)
다이나믹 프로그래밍 (Dynamic Programming) : DP 개념 : 문제를 더 작은 단위로 쪼개어 해결하는 알고리즘. (분할 정복 알고리즘과 비슷하다. 차이점은 바로 아랫줄.) 핵심은, 그 작은 단위의 문제들이
infinitt.tistory.com
3. 최장 공통 부분 순서-> 두 데이터를 비교할 때 유용하다
-순서: 정렬되어 있는 객체의 목록
-부분 순서: 순서에서 일부 요소를 제거한 것
-공통 부분 순서: 두 순서 사이에 공통적으로 존재하는 부분순서
-최장 공통 부분순서: 여러개의 공통 부분순서 중에서 가장 긴것을 가리킨다
(1) LCS 알고리즘
먼저 최적 부분 구조로 이루어져있는지 확인하기
: 위 점화식은 X와 Y의 LCS가 부분 LCS의 답으로부터 만들어지고 있음을 보여준다. 따라서 이 알고리즘은 최적부분구조를 가지므로 동적 계획법으로 해를 구하는 것이 가능하다
-LCS 테이블의 크기는 (i+1)x(j+1). 아무것도 없는 행(i=0)과 열(j=0)을 표현하기 위함.
+ 이렇게 코드를 구현하면 수행시간이 지수적으로 증가함. O(2^(n+m))만큼
(2) 동적계획법으로 설계하는 LCS 알고리즘 -> LCS의 길이를 구할 수 있음
(3) LCS 자체를 구하는 방법
- 오른쪽/아래 모서리 요소를 시작 셀로 지정하고, LCS의 요소를 담기 위한 리스트를 하나 준비한다
- 현재위치한 셀의 값이 왼쪽, 왼쪽 위, 위 셀의 값보다 크면 현재 셀의 값을 리스트의 헤드에 삽입하고 왼쪽 위 셀로 이동한다
- 현재 위치한 셀의 조건이 단계 ㄴ.에 해당하지 않으며, 현재 셀의 값과 왼쪽 셀의 값이 같고 위 셀의 값보다 큰 경우에는 왼쪽으로 이동한다. 이동만 할 뿐 리스트에 아무것도 넣지 않는다
- 2,3번째 중 어느 경우에도 해당하지 않는 경우에는 위 셀로 이동. 리스트에 아무것도 안 넣음
- i=0 or j=0 이 될때까지 ㄱ~ㄹ 단계 반복