'2015/04/26'에 해당되는 글 2건

  1. 2015.04.26 더블릿_줄 세우기
  2. 2015.04.26 증가하는부분수열(Longest Increase Subsequence)

백준에서 똑같은 문제 7570_줄세우기는 실패했다.. 이유는 무엇일까? 


이 문제는 정말 어떻게 푸는지를 몰라서 헤맸고, 결국 인터넷을 통해 풀이법을 공유 받았는데도 이해가 안 가는 문제다. 

학생들의 번호를 인덱스로 가지는 배열을 가지고 동적계획법을 활용한 문제인 것은 같으나

그 로직에 대해서 100% 이해가 가지 않는다. 


우선, 문제의 핵심은 

줄을 세울 때 맨 뒤로 보내거나, 맨 앞으로 보내는 개수의 최소 값을 구하라는 것인데

가장 긴 증가하는 학생들의 수열을 구한 후에 전체 학생 수에서 빼주면 그 것이 최소로 학생들을 맨 뒤로 보내거나,

맨 앞으로 보내게 되는 것이었다. 

대충 이해는 가겠으나, 이 것을 코드를 옮기는데 잘 되지 않아,,,(예제 테스트케이스는 맞았으나 그 다음부터 잘 안되어서

다른 코드를 참고 했는데, 보고도 잉?)


나와는 다르게 입력 받은 번호를 인덱스로 활용해서 동적으로 학생들의 증가하는 수열을 구하는 방법이었다. 


예제의 테스트케이스를 이용해 설명하자면

5

5 2 4 1 3

1) 입력 5가 들어왔을 때

dy[5] = dy[5 - 1] + 1   // 4번째 학생까지 연속되는 수열 개수 + 1

dy[2] = dy[2 - 1] + 1    // 1번째 학생까지 연속되는 수열 개수 + 1

dy[4] = dy[4 - 1] + 1    // 3번째 학생까지 연속되는 수열 개수 + 1

dy[1] = dy[1 - 1] + 1    // 0번째학생까지(0번째학생은 없다) 연속되는 수열 개수 + 1 => 1

..

입력되는 순서 대로 값이 들어갈 것이므로 완전 머리를 잘 쓰신 분이 짜신 코드 같다. 

'알고리즘문제풀이' 카테고리의 다른 글

2529_부등호  (0) 2015.04.27
더블릿_토마토  (0) 2015.04.27
더블릿_고기잡이, 7573_고기잡이  (0) 2015.04.24
더블릿_개미  (0) 2015.04.24
더블릿_로 봇  (0) 2015.04.24
Posted by slender ankles
,
동적 계획법에 대한 예 중에 대표적인 것이 증가하는 부분 수열 문제이다. 
감소하는 부분 수열 문제 역시 둘 다 똑같은 개념이라고 할 수 있겠다. 
예를 들어 

수열

10, 20, 40, 30, 70, 50, 60이 있다고 한다면

이 중에서 증가하는 부분 수열 중에 가장 긴 것을 찾아라. 

라는 것이 증가하는 부분 수열이라고 하겠다. 

-----n^2 방법--------

간단히 n^2으로 풀 수 있는 소스를 설명하자면, 

(이 부분도 간단히 생각해내기 어려웠다. 동적계획법으로 푸는 n^2 이다)

정말 간단하고 쉬운 방법은 n! 완전탐색이겠다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
 
int arr[7= { 10204030705060 };
int dy[8];
int n = 7;
 
int main(){
    for (int i = 1; i <= n; i++){
        for (int j = 0; j < i; j++){
            if (arr[j] < arr[i] && dy[i] < dy[j] + 1){
                dy[i] = dy[j] + 1;
            }
        }
    }
        sort(dy, dy + n);  // 중요
    cout << dy[n - 1<< endl;
 
    return 0;
}
cs


10, 20, 40, 30, 70, 50, 60

기준이 되는 i값을 빨간색, 

그 앞의 값들 j값들을 주황색으로 표현해서 설명하자면, 

(1) i = 1 일 때

10, 20, 40, 30, 70, 50, 60

=> dy[7] = {0, 1, 0, 0, 0, 0, 0};

(2) i = 2일 때

1020, 40, 30, 70, 50, 60

=> dy[7] = {0, 1, 2, 0, 0, 0, 0};

(3) i = 3일 때

102040, 30, 70, 50, 60

=> dy[7] = {0, 1, 2, 2, 0, 0, 0};

(4) i = 4일 때

10204030, 70, 50, 60

=> dy[7] = {0, 1, 2, 2, 3, 0, 0};

(보충설명) 70이 가지는 증가하는 부분 수열 10, 20, 40, 70이다. 

.......


써보면서 알게 되었는데, 최대 증가하는 부분 수열은 연속된 것을 고려하지 않는 듯 하다. 

연속 된 것을 찾기 위한 알고리즘은 아닌 듯 하다. 


20보다 작은 인덱스들을 처음부터 돌아다니면서 

20보다 작고 (arr[i] > arr[j]) ,현재 자신이 가지고 있는 증가수열의 개수보다 크면(dy[i] < dy[j] + 1) 

갱신

.....

Sort(정렬)를 반드시 해야 한다. 

대충 감이 올지 모르겠다. 나도 글을 써보니까 이해가 될 듯 하다. 


-----n*logn 방법--------

1)Lower Bound 방법

Lower Bound란 허용되는 하한값을 가진다는 것을 말한다. 

결국 입력 되는 값들을 고대로 인덱스로 가지면서 연산을 해주면 된다는 것이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
 
int arr[5= {52413};
int dy[110000];
int n = 5;
 
int main(){
    for (int i = 0; i < n; i++){
        dy[arr[i]] = dy[arr[i] - 1+ 1;
    }
    for (int i = 0; i < 5; i++){
        cout << dy[arr[i]] << " ";
    }
    cout << endl;
    return 0;
}                                                            
cs



Posted by slender ankles
,