
문제
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.
예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.
첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.
둘째 줄에는 정답이 될 수 있는 가장 긴 증가하는 부분 수열을 출력한다.
14003번: 가장 긴 증가하는 부분 수열 5
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)
www.acmicpc.net
문제조건
- N (1 ≤ N ≤ 1,000,000)
- -1,000,000,000 ≤ Ai ≤ 1,000,000,000
풀이
12738번: 가장 긴 증가하는 부분 수열 3을 꼭 먼저 풀고 풀어야 하는 문제이다. 이 문제에서 LIS의 길이는 구할 수 있었지만 정확한 LIS(Longest Increasing Subsequence)를 구하지는 못했다. 예를 들어 A = { 10, 40, 50, 30 }에 대한 증가하는 배열 V를 구해보면 [10] -> [10, 40] -> [10, 40, 50] -> [10, 30, 50]으로 원하는 답인 [10, 40, 50]과 다른 답이 나오는 것을 확인 할 수 있었다.
플레티넘 문제 답게 LIS 알고리즘과 dp를 함께 사용해야 정답을 구할 수 있었다. 위 예시에서 원하는 답이 나오지 않는 이유는 이미 답이 구해졌지만 계속해서 값을 확인하기 때문이다. 따라서 가장 마지막 값을 저장해 놓으면 이를 방지할 수 있다. dp배열에 V배열에서의 위치를 기록해 놓는다. 이후 dp배열을 마지막부터 돌며 가장 큰 값을 뽑아내면 구하고자 하는 LIS를 거꾸로 구할 수 있다.
예시
A = {10, 20, 10, 30, 20, 50}
10 | 20 | 10 | 30 | 20 | 50 |
✅ 0 | ✅ 1 | 0 | ✅ 2 | 1 | ✅ 3 |
A = {10, 40, 50, 30}
10 | 40 | 50 | 30 |
✅ 0 | ✅ 1 | ✅ 2 | 1 |
코드
#include <iostream> #include <algorithm> #include <vector> using namespace std; int N, cnt; int arr[1000001], dp[1000001]; vector<int> v, ans; int main() { cin >> N; for (int i = 1; i <= N; i++) cin >> arr[i]; v.push_back(arr[1]); for (int i = 2; i <= N; i++) { if (v[cnt] < arr[i]) { v.push_back(arr[i]); cnt++; dp[i] = cnt; } else { // 같거나 작은 위치를 lower_bound로 찾음 int pos = lower_bound(v.begin(), v.end(), arr[i]) - v.begin(); v[pos] = arr[i]; dp[i] = pos; } } // 값 복원 int LIS = cnt; for (int i = N; i >= 0; i--) { if (dp[i] == LIS) { ans.push_back(arr[i]); LIS--; } } int size = ans.size(); cout << size << '\n'; for (int i = 0; i < size; i++) { cout << ans.back() << " "; ans.pop_back(); } }
'알고리즘 > BOJ' 카테고리의 다른 글
[백준] 9328번: 열쇠 (c++) (0) | 2021.10.19 |
---|---|
[백준] 2239번: 스도쿠 (c++) (0) | 2021.10.13 |
[백준] 12738번: 가장 긴 증가하는 부분 수열 3 (c++) (0) | 2021.10.07 |
[백준] 2623번: 음악프로그램 (c++) (0) | 2021.10.06 |
[백준] 7579번: 앱 (c++) (0) | 2021.09.30 |