C++ / 백준 / 14002 / 가장 긴 증가하는 부분 수열 4
문제
https://www.acmicpc.net/problem/14002
14002번: 가장 긴 증가하는 부분 수열 4
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이
www.acmicpc.net
문제풀이
가장 긴 증가하는 부분 수열 다른 문제부터 풀면 편하다
해당 문제: https://www.acmicpc.net/problem/11053
해당 문제풀이: https://githubseob.tistory.com/17
현재 숫자가 n일 때 1부터 n-1까지 돌면서 최장 길이를 찾고 DP[n][0]에, n을 제외한 최장 길이의 끝 숫자를 DP[n][1]에 집어넣고 반복문이 종료되면 최장 길이를 찾고 스택에 집어넣으면서 후입 선출을 이용해서 풀었다.
for (y = 0; y < N; ++y) {
for (x = 0; x < y; ++x) {
if (Arr[x] < Arr[y]) {
if (DP[y][0] <= DP[x][0]) {
DP[y][0] = DP[x][0] + 1;
DP[y][1] = x;
}
}
}
}
현재 숫자가 y이면 x는 0부터 y-1까지 돌면서 입력받은 배열 값보다 작은 숫자들을 찾는다.
그중 현재 숫자보다 DP값이 큰 x값을 찾을 때마다 y의 DP값을 DP[x][0] +1로 바꾼고 그때의 x값을 DP[y][1]에 저장한다.
이러면 y일 때 가장 긴 부분 수열의 길이가 DP[y][0]에 저장되고, 바로 직전의 x값이 DP[y][1]에 저장된다.
for (x = 0; x < N; ++x) {
if (big < DP[x][0]) {
big = DP[x][0];
big_x = x;
}
}
DP[x][0]를 돌면서 가장 긴 부분 수열의 길이를 찾고 그때 x를 big_x에 저장한다.
for (big; big > 0; --big) {
seq.push(Arr[big_x]);
big_x = DP[big_x][1];
}
while (!seq.empty()) {
cout << seq.top() << " ";
seq.pop();
}
답은 작은 수부터 출력해야 하므로 후입 선출인 스택에 집어넣는다.
50을 집어넣고 DP[5][1]값인 3을 입력받는다.
DP[3][0] = 30을 집어넣고 1을 입력받는다. 이런 식으로 길이만큼 반복한다.
스택에 모든 값을 집어넣었으면 스택의 top부분을 빌 때까지 출력한다.
코드
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int N = 0;
int y = 0, x = 0;
cin >> N;
vector<int>Arr(N, 0);
vector<vector<int>>DP(N, vector<int>(2, 1));
stack<int>seq;
for (x = 0; x < N; ++x) {
cin >> Arr[x];
}
for (y = 0; y < N; ++y) {
for (x = 0; x < y; ++x) {
if (Arr[x] < Arr[y]) {
if (DP[y][0] <= DP[x][0]) {
DP[y][0] = DP[x][0] + 1;
DP[y][1] = x;
}
}
}
}
int big = 0;
int big_x = 0;
for (x = 0; x < N; ++x) {
if (big < DP[x][0]) {
big = DP[x][0];
big_x = x;
}
}
cout << DP[big_x][0] << "\n";
for (big; big > 0; --big) {
seq.push(Arr[big_x]);
big_x = DP[big_x][1];
}
while (!seq.empty()) {
cout << seq.top() << " ";
seq.pop();
}
}