PS/BOJ2022. 4. 25. 22:35

가장 긴 바이토닉 부분 수열

 

 

10
ARR : 1 5 2 1 4 3 4 5 2 1

LIS  : 1 2 2 1 3 3 4 5 2 1 
LDS : 1 5 2 1 4 3 3 3 2 1 

DP = LIS[i] + LDS[i] - 1 

DP  :  1 6 4 1 6 5 6 7 3 1

 

LIS값을 나타내는 부분수열.

{1} , 1

{1,5}, 2

{1,2}, 2

{1}, 1

{1,2,4} , 3

{1,2,3} , 3

{1,2,3,4}, 4

{1,2,3,4,5}, 5
{1,2} 2

{1}, 1

 

LDS를 나타내는 부분 수열.
{1}, 1
{5,4,3,2,1}, 5
{2,1}, 2
{1}, 1
{4,3,2,1}, 4
{3,2,1}, 3
{4,2,1}, 3
{5,2,1}, 3
{2,1}, 2
{1}, 1

 

 

LDS  + LIS 합해보면 아래와 같이 절묘하게 하나의 중복요소가 존재하는 배열의 길이가 된다. 

 

예를 들어 생각을 해보면.... 

ex)

{5,4,3,2,1},5  {1,5}, 2 

LDS를 구하면.. 5,4,3,2,1 이후 5기준으로(포함한) 나머지 요소에서의 LIS는 1,5

두 배열을 합하고 5를 하나 빼주면 6이런 방식으로 풀이된다.

 

최종적으로 다 계산해보면

{1},1           {1} , 1               
{5,4,3,2,1},5  {1,5}, 2
{2,1},2         {1,2}, 2
{1},1           {1}, 1
{4,3,2,1},4    {1,2,4} , 3
{3,2,1},3      {1,2,3} , 3
{4,2,1},3      {1,2,3,4}, 4
{5,2,1},3      {1,2,3,4,5}, 5
{2,1},2        {1,2} 2
{1},  1        {1},  1

 

아래와 같이 겹치는 요소하나를 제거해주면 바이토닉 수열이 나온다.

LDS  + LIS -1
{1},            1
{1,5,4,3,2,1}, 6
{1,2,1},        3
{1},             1
{1,2,4,3,2,1},  6
{1,2,3,2,1},    5
{1,2,3,4,2,1},  3
{1,2,3,4,5,2,1},7
{1,2,1},         3
{1},             1

 

이전 LIS, LDS를 구할 때, dp 테이블의 값을 내마음대로 정의해서 썼는데 그 경우엔 이렇게 바이토닉을 구할 수 없다.

(LDS + LIS -1 연산을 할 때 예외가 발생하겠지) 

따라서 이런 응용 문제를 해결하기 위해서라도 정형화 또는 정석적인 방식으로만 익히는게 더 좋은 학습법이라 생각된다.  (아래의 LIS,LDS를 잘 기억하도록)

 

 

//11054

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
   //https://st-lab.tistory.com/136
   static Integer[] arr;
   static Integer[] rdp;
   static Integer[] ldp;
   static Integer[] dp;

   public static void main(String[] args) throws IOException {

      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      StringTokenizer st = new StringTokenizer(br.readLine());

      int N = Integer.parseInt(st.nextToken());
      arr = new Integer[N];
      rdp = new Integer[N];
      ldp = new Integer[N];
      dp = new Integer[N];

      st = new StringTokenizer(br.readLine());
      for (int i = 0; i < N; ++i)
         arr[i] = Integer.parseInt(st.nextToken());

      /* TopDown
      for (int i = 0; i < N; ++i) {
         LIS(i, rdp);
         LDS(i, ldp);
      }
      //
      */
      //Bottom-UP         
      for ( int i = 0 ; i < N ; ++i) {
         rdp[i]=1;
         for (int j = 0; j < i ; ++j) {
            if ( arr[j] < arr[i])
               rdp[i] = Math.max(rdp[i], rdp[j] + 1);
         }
         
      }
      for ( int i = N-1 ; i >= 0 ; --i) {
         ldp[i]=1;
         for (int j = N-1; j > i  ; --j) {
            if ( arr[j] < arr[i])
               ldp[i] = Math.max(ldp[i], ldp[j] + 1);
         }
         
      }

      
      int max = Integer.MIN_VALUE;
      for ( int i = 0 ; i < N ; ++i) {
         max = Math.max(max,rdp[i] + ldp[i] - 1);         
      }
      
      System.out.println(max);
      br.close();
      

   }

   static int LIS(int n, Integer[] dp) {
      if (dp[n] == null) {
         dp[n] = 1;
         for (int i = n - 1; i >= 0; --i) {
            if (arr[i] < arr[n]) {
               dp[n] = Math.max(dp[n], LIS(i, dp) + 1);
            }
         }

      }
      return dp[n];
   }

   static int LDS(int n, Integer[] dp) {

      if (dp[n] == null) {
         dp[n] = 1;
         for (int i = n + 1; i < arr.length; ++i) {
            if (arr[i] < arr[n])
               dp[n] = Math.max(dp[n], LDS(i, dp) + 1);
         }
      }

      return dp[n];
   }

}

ex)
10
1 5 2 1 4 3 4 5 2 1

LIS : 1 2 2 1 3 3 4 5 2 1 
LDS : 1 5 2 1 4 3 3 3 2 1 

7

 

 

출처 : [백준] 11054번 : 가장 긴 바이토닉 부분 수열 - JAVA [자바] (tistory.com)

'PS > BOJ' 카테고리의 다른 글

2579  (0) 2022.04.25
1912  (0) 2022.04.25
11722  (0) 2022.04.25
11055  (0) 2022.04.24
11053  (0) 2022.04.24
Posted by easy16