1. LIS(최장 증가 부분 수열 ; Longest Increasing Subsequence)
부분 수열은 수열의 일부 숫자를 지우고 남은 수열이다.
(단, 수열의 순서가 변경되면 안됨)
순 증가 부분 수열은 수열의 배열이 증가하는 형태인 수열이다.
(ex. 1, 3, 5는 순 증가 부분 수열, 1, 3, 7, 4는 순 증가 부분 수열이 아니다)
LIS는 제일 긴 순 증가 부분 수열을 뜻한다.
즉 수열에서 가장 긴 순 증가 부분 수열의 길이를 찾는 것이 목표이다.
2. 코드 분석
#include <iostream>
#include <windows.h>
#include <vector>
using namespace std;
int cache[100];
vector<int> seq = { 1,9,2,5,7 };
// 문제가 요구하는 정답을 반환한다
int LIS(int pos) // pos번 인덱스가 포함이 된 부분 수열을 만든다
{
// 예외 사항 확인
// 캐시 확인
int& ret = cache[pos];
if (ret != -1)
return ret;
// Seq : 1 9 2 5 7
// 최소한 seq[pos]는 1부터 시작해야 함
ret = 1;
// 정답 구하기
for (int next = pos + 1; next < seq.size(); next++)
if (seq[pos] < seq[next])
ret = max(ret, 1 + LIS(next));
return ret;
}
int main()
{
// 길이일 리 없는 값으로 초기화하기
std::memset(cache, -1, sizeof(cache));
int ret = 0;
for (int pos = 0; pos < seq.size(); pos++)
ret = max(ret, LIS(pos));
}
(1) 캐시 확인하기
cache는 요소가 100개인 배열로 이루어져있다. 이 캐시는 main 함수에서 -1로 초기화 된다.
ret는 cache 배열을 참조하게 되어있어, ret로 값을 구하면 cache에 하나씩 값을 저장할 수 있다.
(2) 정답 구하기
next 인덱스를 사용하여 처음 0번째 수 부터 seq 배열의 끝까지 반복한다.
순 증가 부분 수열을 충족하기 위해 지금(pos) 값이 다음(next)보다 작아야 한다.
조건을 만족하면 ret는 LIS로 구해진 길이와, 다음 인덱스를 재귀적으로 호출한 길이와 비교하여 더 큰 값을 취한다.
(3) 재귀적 호출
ex) seq = {1, 9, 2, 5, 7}
부분 배열은 최소한 하나의 요소가 존재하여야 하므로 ret의 기본값은 1이다.
순 증가 부분 수열의 조건을 만족하는 경우, 길이를 1 증가시킴과 동시에 그 다음 인덱스의 값과 방금 구한 값을 이용해
다시 순 증가 부분 수열의 조건을 만족하는지 확인한다.
그리고 순 증가 부분 수열의 조건을 만족하지 못하면 ret을 반환한다.
(1, 9) -> 만족 -> (1, 9, 2) -> 불반족, ret = 2 반환
(9, 2), (9, 3), (9, 7) -> 불만족, ret = 1 반환
(2, 5) -> 만족 -> (2, 5, 7) -> 만족, ret = 3 반환
(5, 7) -> 만족 -> ret = 2 반환
(1, 2) -> 만족 -> (1, 2, 5) -> 만족 -> (1, 2, 5, 7) -> 만족 -> ret = 4 반환
(이하 생략)
max 함수를 사용하여 가장 큰 값을 추출하기 때문에 결과값은 4가 반환된다.
'자료구조와 알고리즘 > 동적 계획법' 카테고리의 다른 글
7-5. 동적 계획법 예제 문제 - #4. 강화하기 (0) | 2023.08.01 |
---|---|
7-4. 동적 계획법 예제 문제 - #3. Tic-Tac-Toe(틱택토) (0) | 2023.08.01 |
7-3. 동적 계획법 예제 문제 - #2. TRIANGLE_PATH(삼각형 위의 최대경로) (0) | 2023.07.26 |
7-1. 동적 계획법(Dynamic Programming) (0) | 2023.07.26 |