Baekjoon Review

[Gold 4] 11054 가장 긴 바이토닉 부분 수열

hanseongbugi 2024. 9. 23. 21:49

https://www.acmicpc.net/problem/11054

 

바이토닉 부분 수열은 DP를 사용해 구할 수 있다.

바이토닉 부분 수열을 살펴보면 

증가하는 수열 부분과 감소하는 수열 부분이 있다는 것을 알 수 있다.

이는 A[i]까지 증가하는 부분 수열과 A[i]부터 감소하는 부분 수열을 구하면 된다는 것을 알 수 있다.

 

A[i]까지 증가하는 부분 수열은 다음과 같이 구한다.

// 증가하는 수열 중 가장 긴 것
    for(int i = 0;i<N;i++){
        dp[i] = 1;
        for(int j = 0;j<=i;j++){
            if(A[j] < A[i] && dp[i] < dp[j] + 1)
                dp[i] = dp[j] + 1;
        }
    }

 

초기 A[i]인 경우 부분 수열의 길이는 1이 되므로 dp[i]를 1로 초기화한다.

이후 0번째 인덱스부터 i 번째 인덱스까지 A배열에 존재하는 값을 비교한다.

A[i] 기준으로 이전에 존재하는 값들이 작고

dp[i]의 값이 이전에 존재한는 값들의 dp보다 작은 경우

dp[i]를 갱신하게 된다. 

 

감소하는 부분 수열은 증가하는 부분 수열과 유사하다.

 

#include <iostream>
using namespace std;

int N;
int A[1000];

int dp[1000];
int rdp[1000];
int answer = 0;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>N;
    for(int i = 0;i<N;i++)
        cin>>A[i];
    
    // 증가하는 수열 중 가장 긴 것
    for(int i = 0;i<N;i++){
        dp[i] = 1;
        for(int j = 0;j<=i;j++){
            if(A[j] < A[i] && dp[i] < dp[j] + 1)
                dp[i] = dp[j] + 1;
        }
    }

    // 감소하는 수열 중 가장 긴 것
    for(int i = N-1;i>=0;i--){
        rdp[i] = 1;
        for(int j = N-1;j>=i;j--){
            if(A[i] > A[j] && rdp[j] + 1 > rdp[i])
                rdp[i] = rdp[j] + 1;
        }
    }

    for(int i = 0;i<N;i++)
        answer = max(answer,dp[i] + rdp[i] - 1);
    
    cout<<answer;
}