본문 바로가기
백준_JAVA

[백준] 11053번 - 가장 긴 증가하는 부분 수열

by stonage 2023. 5. 21.

 

 

11053번: 가장 긴 증가하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이

www.acmicpc.net

 

 

 

다이나믹프로그래밍을 사용하여 해결할 수 있는 문제이다. 

 

문제에서 요구하는 것은 가장 긴 '증가하는 부분 수열'이다. 부분 수열은 연속적이지 않아도 되기 때문에 처음 문제를 접했을 때는 쉽게 풀지 못했던 기억이 있다. 이 문제를 접하기 이전의 비슷한 문제들의 경우 문제에서 어느정도의 연속성은 보장해주었기 때문이다. 

 

문제에서 주어진 예시를 보면 수열 10, 20, 10, 30, 20, 50 에서 가장 긴 증가하는 부분 수열은 10, 20, 30, 50이다.

예시에서는 운이 좋게 수열의 마지막 숫자가 최대값이어서 가장 긴 증가하는 부분 수열에 포함되었지만 경우에 따라서는 포함되지 않을 수도 있다. (10, 20, 30, 10 과 같은 수열)

이를 통해서 세워볼 수 있는 가설은 수열의 모든 요소에 대해서 해당 요소가 가장 긴 증가하는 부분 수열의 최대 값인 경우를 모두 비교해봐야 답을 구할 수 있을 것이라는 것이다.

 

문제에 주어진 조건을 통해 세운 점화식은 다음과 같다.

수열 A의 n번째요소인 A[n]가 최대값이고 LIS가 A[n]이 가장 긴 증가하는 부분 수열의 최대값을 반환할 때

만약 A[n-1] < A[n] 이라면 A[n-1] 이 최대값인 가장 긴 증가하는 부분 수열에 +1 한 값을 LIS이 반환한다. 

그러나 A[n-1] >= A[n] 이라면 A[n-2] 와 A[n]과의 관계를 비교한다. 이 과정을 수열의 첫 번째 요소까지 반복하면서 A[n]이 최대값일 때의 가장 긴 증가하는 부분 수열의 길이를 구한다.

 

위 점화식을 수열의 모든 요소들에 대하여 계산을 한다면, LIS가 재귀호출 되면서 같은 연산을 반복해야 하므로 다이나믹 프로그래밍을 사용하여 n번째 수열이 부분 수열의 최대인 경우의 부분수열의 길이를 dp[n] 에 저장한다.

 

int max = 0;
        
for (int i=1; i<=N; i++) max = Math.max(max, LIS(i));


////////////////////////////////////////////////////////////////////////////////
static int LIS (int N) {
        
    if (dp[N] == null) {
		
        // 부분수열의 최소 길이는 1이므로 dp[N]의 최소값도 1이다.
        dp[N] = 1;
        int idx = N - 1;

        while (idx > 0) {
            if (A[idx] < A[N]) 
                dp[N] = Math.max(dp[N], LIS(idx) + 1);
            idx--;
        }
    }

    return dp[N];
}

 

 

 

 

전체 코드

import java.util.*;
import java.io.*;

public class Main {
    
    static int[] A;
    static Integer[] dp;
    
    public static void main (String[] args) throws IOException {
        
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int N = Integer.parseInt(br.readLine());
        A = new int[N+1];
        dp = new Integer[N+1];
        
        dp[1] = 1;
        
        
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i=1; i<=N; i++) A[i] = Integer.parseInt(st.nextToken());
        
        
        int max = 0;
        
        for (int i=1; i<=N; i++) max = Math.max(max, LIS(i));
        
        
        System.out.println(max);
        
        br.close();
    }
    
    static int LIS (int N) {
        
        if (dp[N] == null) {
            
            dp[N] = 1;
            int idx = N - 1;
            
            while (idx > 0) {
                if (A[idx] < A[N]) 
                    dp[N] = Math.max(dp[N], LIS(idx) + 1);
                idx--;
            }
        }
        
        return dp[N];
    }
}

 

'백준_JAVA' 카테고리의 다른 글

[백준] 9251번 - LCS  (1) 2023.05.22
[백준] 2565번 - 전깃줄  (0) 2023.05.21
[백준] 2156번 - 포도주 시식  (0) 2023.05.21
[백준] 1932번 - 정수 삼각형  (0) 2023.05.19
[백준] 11729번 - 하노이 탑 이동 순서  (0) 2023.05.19