백준의 상자넣기(1965) 문제이다.

( 문제 바로가기 )


[ 문제풀이 ]

1) 이 문제를 쉽게 말하자면 주어진 수열에서 "가장 긴 증가하는 부분수열"을 구하는 문제이다.

   본인은 이 문제를 해결하기 위해서 입력을 저장하는 배열 Arr[] 1차원 배열과, 최대의 상자갯수를 저장하는 DP[] 배열을

   사용하였다.

   DP[a] = b 의 의미는, "a번 원소까지의 담을 수 있는 최대의 상자갯수는 b개 입니다." 이다.


2) { 1, 2, 5, 4, 7 } 이라는 예제를 통해서 풀이과정을 알아보자.

   먼저 초기 값으로 DP[1] ~ DP[5] = 1 로 저장을 해줘야 한다. 왜냐하면, 자기자신을 선택하는 순간 상자의 갯수는

   자기자신, 최소 1개는 되기 때문이다.

   그렇다면, 지금부터는 첫번째 원소부터 다섯 번째 원소까지 각 원소들을 선택했을 때의 상자의 최댓값을 알아보자.

   최댓값을 구하는 방법은, "자기 자신보다 이전에 있던 원소들을 비교해서 더 작은 값들 중에, 그 원소의 최댓값 + 1을

   한 것이, 기존의 값 보다 더 크다면 선택을 한다." 이다.

   무슨 말인지 하나도 모르겠다. 위의 말을 예를 통해서 구체적으로 알아보자.

   지금부터는 위의 예제의 첫 번쨰 원소부터 다섯 번째 원소까지의 상자의 최댓값을 알아볼 것이다.

   < 첫번째 원소 : 1 >

   사실, 첫 번째 원소 '1' 의 경우 비교할 대상이 없다. 왜냐하면, "자기 자신보다 이전에 있던 원소들을 비교해서 더 작은 값들

   중에.." 라는 말의 조건을 충족시키는 '이전에 있던 원소'가 없기 때문이다.

   그렇다면 DP[1] = 1 로 그대로 남아있을 것이다.

   < 두번째 원소 : 2 >

   "자기 자신보다 이전에 있던 원소들을 비교해서 더 작은 값들 중에..."

   두번째 원소인 '2'보다 이전에 있던 원소로는 '1'이 있다. 게다가, '1'은 더 '2'보다 더 작은 값이다.

   "그 원소의 최댓값 + 1을 한 것이, 기존의 값 보다 더 크면 선택을 해라 !"

   그 원소의 최댓값은 1이다. 첫번째 상자에 담을 수 있는 상자의 최대갯수는 1개이기 때문이다.

   즉, 그 원소의 최댓값 + 1 = 2

      기존의 값 = 1 (DP[2]의 값)

      그 원소의 최댓값 + 1을 한 '2' 라는 값이, 기존의 값 '1' 보다 더 크기 때문에 선택을 해라.

      즉, DP[2] = 2 가 되는 것이다.

   실제로, 두 번째 원소인 '2'를 선택했을 때 담을 수 있는 상자의 최댓값은 2개이다. { 1, 2 } !

   < 세번째 원소 : 5 >

   '5' 보다 이전의 원소들 중 더 작은 값들로는 '1'과 '2' 가 있다.

   먼저 '1'을 비교해보자.

   그 원소의 최댓값 + 1을 한 값이, 기존의 값 보다 더 크다면 선택을 한다.

   DP[1] = 1 이고 이 값에다가 +1을 한 '2'라는 값이, 기존의 값인 DP[3] = 1 보다 크기 때문에 선택을 하게 되면

   DP[3] = 2 가 된다.

   이제는 '2'를 비교해보자.

   그 원소의 최댓값 + 1을 한 값이, 기존의 값 보다 더 크다면 선택을 한다.

   DP[2] 의 값은 현재 2이다. 여기에 + 1을 한 값인 '3' 이라는 값이, 기존의 값인 '2' 보다 더 크기 때문에

   DP[3] = 3 이 된다.

   < 네번째 원소 : 4 >

   4 보다 이전에 있는 원소이면서 더 작은 값 = '1', '2'

   '1'을 선택할 경우 DP[4] = 2

   '2'를 선택할 경우 DP[4] = 3 이 된다. 위의 설명을 읽고 다시 스스로 한번 해보자.

   < 마지막 원소 : 7 >

   7보다 이전에 있는 원소이면서 더 작은 값 = '1', '2', '5', '4'

   '1' 을 선택할 경우 DP[5] = 2

   '2' 를 선택할 경우 DP[5] = 3

   '5' 를 선택할 경우 DP[5] = 4

   '4' 를 선택할 경우 DP[5] = 4

  

   이 후, 이 모든 값을 비교해서 최댓값을 찾아주면 된다.

   마지막으로 풀이를 정리해보자면..

  1. 자기보다 이전의 원소들 중 작은 원소들을 하나씩 모두 비교해보자.

  2. 선택한 작은 원소의 최댓값 + 1을 한 값이, 현재 자기자신의 최댓값 보다 크다면 그 값으로 자기자신의 값을

    갱신

  3. 최댓값을 갱신 !


[ 소스코드 ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<iostream>
 
#define endl "\n"
#define MAX 1000 + 1
using namespace std;
 
int N;
int Arr[MAX];
int DP[MAX];
 
void Input()
{
    cin >> N;
    for (int i = 1; i <= N; i++)
    {
        cin >> Arr[i];
    }
}
 
void Solution()
{
    int max = 0;
    for (int i = 1; i <= N; i++)
    {
        DP[i] = 1;
        for (int j = 1; j < i; j++)
        {
            if (Arr[j] < Arr[i] && DP[i] < DP[j] + 1)
            {
                DP[i] = DP[j] + 1;
            }
        }
        if (max < DP[i]) max = DP[i];
    }
    cout << max << endl;
}
 
void Solve()
{
    Input();
    Solution();
}
 
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    //freopen("Input.txt", "r", stdin);
    Solve();
 
    return 0;
}
cs











'[ BOJ Code ] > # BOJ -' 카테고리의 다른 글

[ 백준 12886 ] 돌 그룹 (C++)  (2) 2019.02.03
[ 백준 1339 ] 단어수학 (C++)  (0) 2019.02.02
[ 백준 1063 ] 킹 (C++)  (2) 2019.02.02
[ 백준 2239 ] 스도쿠 (C++)  (0) 2019.02.02
[ 백준 2225 ] 합분해 (C++)  (4) 2019.02.01

+ Recent posts