(출처: 종만북)
문제 링크: https://algospot.com/judge/problem/read/LIS
부분 수열(Subsequence)이란 수열에서 0개 이상의 숫자를 지우고 남은 수열을 말합니다.
부분 수열에 포함된 숫자들이 순 증가(strictly increasing)할 때 이 부분 수열을 증가 부분 수열(Increasing Subsequence)라고 합니다.
주어진 수열에서 얻을 수 있는 증가 부분 수열 중 가장 긴 것을 찾는 문제를 최대 증가 부분 수열(LIS, Longest Increasing Subsequence) 찾기 문제라고 하며, 매우 유명한 dp 연습문제 중 하나라고 합니다.
\[ lis(start) = S[start]\text{에서 시작하는 부분 증가 수열 중 최대 길이} \]
점화식을 이렇게 세우면 됩니다. 재귀호출때마다 S[start] 뒤에 있고 큰 수들 중 하나를 다음 숫자로 결정한 뒤, 여기서 시작하는 부분 증가 수열의 최대치를 구하면 됩니다.
코드로 쓰면 아래와 같습니다.
int n;
int cache[100], S[100];
// S[start]에서 시작하는 증가 부분 수열 중 최대 길이 반환
int lis(int start) {
int& ret = cache[start];
if (ret != -1) return ret;
ret = 1; // 항상 S[start]는 있으니 길이는 최하 1
for (int next=start+1; next<n; ++next)
if (S[start] < S[next])
ret = max(ret, lis(next) + 1);
return ret;
}
이 코드는 O(n)의 부분 문제를 갖고, 하나 해결할 때마다 O(n) 반복문을 순회하므로 전체 시간복잡도는 O(n^2)가 됩니다.
위 함수를 호출할 때는 항상 시작 위치를 지정해줘야 하니, 각 위치를 순회하면서 최대값을 찾는 코드를 만들어줘야 합니다.
반응형
'Online Judge > 알고스팟' 카테고리의 다른 글
[알고스팟][C++] JLIS: 합친 LIS (0) | 2020.08.22 |
---|---|
[알고스팟][C++] JUMPGAME: 외발 뛰기 (0) | 2020.08.20 |
[알고스팟][C++] FESTIVAL: 록 페스티벌 (0) | 2020.07.24 |
[알고스팟][C++] FIRETRUCKS: 소방차 (0) | 2020.06.22 |
[알고스팟][C++] ROUTING: 신호 라우팅 (0) | 2020.06.20 |