[백준] [C/C++] [★] 14002번 : 가장 긴 증가하는 부분 수열 4

업데이트:

문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.







입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)







출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

둘째 줄에는 가장 긴 증가하는 부분 수열을 출력한다. 그러한 수열이 여러가지인 경우 아무거나 출력한다.







예제 입력 1

6
10 20 10 30 20 50

예제 출력 1

4
10 20 30 50







알고리즘 [ 접근 방법 ]

DP를 사용해 푸는 LIS (Longest Increasing Subsequence)문제이다.

이전에 문제를 점화식으로 바로 바꿔서 풀던 문제와는 직접 일일히 비교를 한뒤 점화식으로 나타내 풀어낼 수 있다.

D[i] = A[1], … , A[i] 까지 수열이 있을 때, A[i]를 마지막으로 하는 가장 긴 부분 수열의 길이 D[i]는 A[i]가 반드시 포함되어야만 한다.

이때 A[?], A[?], … , A[j]는 D[j]라고 나타낼 수 있고 아래 그림같은 과정을 보인다.

이때 D[i] = max ( D[j] ) + 1 , (단, j<i 이고 A[j] < A[i]) 라고 정의 할 수 있다.

★★★여기서 점화식을 세울때 반드시 기억해야할 것이 하나있다!!! 점화식에 또 다른 변수가 들어간다면 반드시 변수의 범위를 지정해줄 필요가 있다!!!

여기까지가 LIS의 길이를 구하는 과정이고, 문제에서는 LIS인 수열까지 출력하라는 문제이므로 추가 조건이 필요하다.




[ 역추적 ] 하나의 값이 다른 하나의 값에 의해서 변화 될 때, 어떤 값에 의해서 변화하는지를 저장해두는 과정을 말하고 보통 재귀함수를 이용해 구현한다.




여기서 D[i]의 값은 어떤 값에 의해서 결정되는지를 역추적 해보면 된다. D[6] = 4인 이유는 i=4일때 D[4]=3이므로 +1을 해서 4가 된것이다. 따라서 D[6]을 결정지은 값은 i=4 이고 이를 새로운 배열 v에 넣어준다.

같은 과정으로 D[5]= 2인 이유는 i=3일때에 의해 결정된 것이므로 i=3을 v에 넣어준다.

즉, V[i] = A[i]의 앞에 와야하는 수의 인덱스 를 의미한다. 이 과정을 역추적이라고 하고 굉장히 많이 사용되는 방법이므로 반드시 알아둬야 한다.

이를 코드로 구현하면 다음과 같다.

// 역추적 재귀함수
void go(int p) {
	// ? -> ? -> ... -> a[v[p]] -> a[p]

	if (p == -1) return;
	go(v[p]);
	cout << a[p] << " ";
}







풀이

#include <iostream>
using namespace std;
int d[1001];
int a[1001];
int v[1001];

// 역추적 재귀함수
void go(int p) {
	// ? -> ? -> ... -> a[v[p]] -> a[p]

	if (p == -1) return; // v[i] 를 -1로 초기화했기때문에
	go(v[p]);
	cout << a[p] << " ";
}

int main() {
	int num;
	cin >> num;


	for (int i = 0; i < num; i++) cin >> a[i];

	for (int i = 0; i < num; i++) {
		d[i] = 1;
		v[i] = -1;
		for (int j = 0; j < i; j++) {
			if (a[j] < a[i] && d[i] < d[j] + 1) {
				d[i] = d[j] + 1;
				v[i] = j;
			}
		}
	}

	int max = d[0];
	int p = 0;

	for (int i = 0; i < num; i++) {
		if (max < d[i]) {
			max = d[i];
			p = i;
		}
	}

	cout << max << endl;
	go(p);
}







댓글남기기