ABOUT ME

https://github.com/chongin12 chongin12@naver.com

Today
Yesterday
Total
  • 02. 2차시 교육
    알고리즘/정올1차교육(17.7.12~17.8.14) 2017. 7. 15. 01:01
    반응형

    01.cpp - 선택구역 뒤집기 ( https://www.acmicpc.net/problem/10804 )

    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
    #include <stdio.h>
    int arr[22];
    int arr2[22];
    int main(){
        for(int i=1; i<=20++i){
            arr[i]=i;
        }
     
        int a, b;
        for(int k=0; k<10++k){
            for(int i=1; i<=20++i){
                arr2[i]=0;
            }
            scanf("%d %d"&a, &b);
            for(int i=a; i<=b; ++i){
                arr2[i-a]=arr[i];
            }
            for(int i=b; i>=a; --i){
                arr[i]=arr2[b-i];
            }
        }
        for(int i=1; i<=20++i){
            printf("%d ", arr[i]);
        }
    }
    cs


    일반적으로 02.cpp 처럼 스왑을 이용해서 바꾸는게 정석이지만 배열 한개를 더 선언해서 다시 역으로 집어넣는 식으로 한번 해봤습니다.


    02.cpp - 선택구역 뒤집기(스왑)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
     
    void reverse(int arr[], const int a, const int b){
        for(int i=a; i<=b/2+1++i){
            swap(arr[a+i], arr[b-i]);
        }
    }
     
    int main(){
        int arr[11]={01,2,3,4,5,6,7,8,9,10};
        int a, b;
        scanf("%d %d"&a, &b);
        reverse(arr, a, b);
        for(int i=1; i<=10++i){
            printf("%d ", arr[i]);
        }
    }
    cs


    algorithm.h에 있는 swap함수를 사용해서 쉽게 풀어봤습니다.


    03.cpp - 정수부분 소수부분 나누기

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>
     
    void decompose(double x, long* int_part, double *frac_part){
        long a;
        double b;
        a=(int)x;
        b=x-(int)x;
        *int_part=a;
        *frac_part=b;
    }
     
    int main(){
        double x=5.66;
        long i;
        double f;
     
        decompose(x, &i, &f);
        printf("%ld %lf", i, f);
    }
    cs


    형변환을 이용하고 call by reference 를 이용한 인자 전달을 활용합니다.


    04.cpp - 포인터를 이용하여 카드 역배치

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
     
    void reverse(int *arr, int a, int b){
        for(int i=a; i<=b/2+1++i){
            swap(*(arr+a+i-1), *(arr+b-i+1));
        }
    }
     
    int main(){
        int arr[11]={01,2,3,4,5,6,7,8,9,10};
        int a, b;
        scanf("%d %d"&a, &b);
        reverse(arr, a, b);
        for(int i=1; i<=10++i){
            printf("%d "*(arr+i));
        }
    }
    cs


    배열에서 인덱스를 사용하지 않고 포인터로 카드 역배치를 구현해본 것입니다.


    05.cpp - Maximam Sub-Array 와 Kadane Algorithm

    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
    #include <stdio.h>
    #define max(a,b) (a)>(b)?(a):(b)
    int dp[10];
    int arr[10];
    int ans;
     
    int k(int n){
        if(dp[n]) return dp[n];
        if(n==0return arr[0];
        else{
            dp[n]=max(arr[n], k(n-1)+arr[n]);
            if(ans<dp[n]){
                ans=dp[n];
            }
            return dp[n];
        }
     
    }
     
    int main(){
        for(int i=0; i<10++i){
            scanf("%d"&arr[i]);
        }
        dp[0]=arr[0];
        ans = arr[0];
        k(9);
        printf("%d", ans);
     
    }
    cs


    *Maximum Sub-Array (최대 구간 합 문제)

    주어진 배열에서 합이 가장 큰 영역을 찾는 문제입니다. 전체탐색으로 풀면 O(n^3)의 시간이 걸립니다. (첫 반복문 : 시작부분, 두번째 반복문 : 끝부분, 세번째 반복문 : 합 구하기)

    하지만 이걸 단숨에 해결할 수 있는 알고리즘이 있습니다.


    *Kadane Algorithm (카데인 알고리즘)

    1. Sub-Array의 맨 앞에서부터 차례대로 더한다. (Sum에 저장)

    2. Sum이 음수가 되는 지점에서는 0으로 초기화한다.

    3. Sum들은 항상 최대값을 유지한다.

    이 세가지 순서로 하면 된다고 위키에 써져있습니다.


    수업시간에 배운 내용은 : 

    이 식이었죠.

    설명을 해보자면, 우선 i는 0부터 n까지 커지는 수 입니다. 가장 앞에 보이는  는 i번째 숫자를 제일 마지막으로 한 연속된 숫자들의 집합의 합 중 가장 큰 것입니다.

    Max는 첫번째 인자와 두번째 인자 중 큰 수를 반환하는 함수죠. 

    에는 i-1번째 숫자를 제일 마지막으로 한 연속된 숫자들의 집합의 합 중 가장 큰 수가 이미 들어가 있습니다.

    여기서, 지금 구하는 에선, 에서 현재 arr[i]의 숫자를 더한 값 혹은 그냥 arr[i]의 숫자 둘 중에 더 큰수를 넣어야 합니다.

    그림으로 그려보면, (맨 앞이 arr[0] = -1 , 맨 끝이 arr[9] = -2)

    이 그림을 자세히 보시면 어떻게 되는 것인지 쉽게 파악이 가능합니다.


    이것을 그대로 for문으로 구현해보자면,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int _for(int n){
        int K[10];
        K[0]=arr[0];
        for(int i=1; i<=n; ++i){
            K[i]=max(K[i-1]+arr[i], arr[i]);
        }
        int biggest=K[0];
        for(int i=0; i<=n; ++i){
            printf(" %d ", K[i]);
            if(K[i]>biggest) biggest=K[i];
        }
     
        return biggest;
    }
    cs

    이렇게 됩니다. 위의 예제는 n이 9입니다. 


    맨 위에 올린 코드는 이것을 dp, Dynamic Programming(동적계획법, 메모이제이션 기술)을 이용해서 재귀함수의 시간을 단축시켰습니다.


    05.cpp

    04.cpp

    03.cpp

    02.cpp

    01.cpp





    반응형

    '알고리즘 > 정올1차교육(17.7.12~17.8.14)' 카테고리의 다른 글

    05. 5차시 수업  (0) 2017.07.27
    04. 4차시 교육  (0) 2017.07.20
    03. 3차시 교육  (0) 2017.07.18
    01. 1차시 교육  (0) 2017.07.13
    00. 교육 일정  (0) 2017.07.13

    댓글

Designed by Tistory.