Algorithm/문제풀이

[다이나믹 프로그래밍] 가장 큰 증가 부분 수열

lee308812 2018. 8. 10. 22:26

문제 링크 : https://www.acmicpc.net/problem/11055


 

시간 제한메모리 제한제출정답맞은 사람정답 비율
1 초256 MB84093789306746.463%

문제

수열 A가 주어졌을 때, 그 수열의 증가 부분 수열 중에서 합이 가장 큰 것을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가 부분 수열은 A = {1, 100, 25060, 3, 5, 6, 7, 8} 이고, 합은 113이다.

입력

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

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

출력

첫째 줄에 수열 A의 합이 가장 큰 증가 부분 수열의 합을 출력한다.

예제 입력 1 

10
1 100 2 50 60 3 5 6 7 8

예제 출력 1 

113


[ 문제 풀이 ]


D[i] = A[i]가 마지막으로 오는 증가 부분 수열 중 가장 큰 합


D[1] = A[1]

D[2] = max(A[2], D[1] + A[2] if A[1] < A[2])

D[3] = max(A[3], D[1] + A[3] if A[1] < A[3], D[2] + A[3] if A[2] < A[3])


...


D[i] = max(D[j] + A[i], if j < i and A[j] < A[i])


ex) D[4] 구하기


D[j]는 A[j]를 반드시 사용하여(A[j]가 마지막으로 오게된다) 만드는 증가 부분 수열 중 가장 큰 합을 저장하고 있다.




[ 최종 구현(C++) ]

#include <stdio.h>
#define MAX_NUMBER 1002
#define MAX(a,b) ((a) > (b) ? (a) : (b))

int A[MAX_NUMBER] = { 0, };
int D[MAX_NUMBER] = { 0, };

int main(void)
{
	int N;
	int result = 0;

	scanf("%d", &N);

	for (register int i = 1; i <= N; i++)
		scanf("%d", &A[i]);

	D[1] = A[1];

	for (register int i = 2; i <= N; i++)
	{
		D[i] = A[i];

		for (register int j = 1; j <= i - 1; j++)
		{
			if (A[j] < A[i])
				D[i] = MAX(D[i], D[j] + A[i]);
		}
	}

	for (register int i = 1; i <= N; i++)
	{
		result = MAX(result, D[i]);
	}

	printf("%d\n", result);

	return 0;
}