본문 바로가기
알고리즘

BOJ 3020 - 개똥벌레(C++)

by 장중앙 2021. 9. 1.

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

 

3020번: 개똥벌레

개똥벌레 한 마리가 장애물(석순과 종유석)로 가득찬 동굴에 들어갔다. 동굴의 길이는 N미터이고, 높이는 H미터이다. (N은 짝수) 첫 번째 장애물은 항상 석순이고, 그 다음에는 종유석과 석순이

www.acmicpc.net

풀이

algorithm 라이브러리에서 제공하는 이진탐색 함수인 lower_bound, upper_bound를 이용하여 풀 수 있음

* 이진탐색을 위해서는 오름차순 정렬이 되어 있어야함

lower_bound(begin, end, target) : target 값 이상의 숫자가 배열 몇 번째에 있는지 탐색

upper_bound(begin, end, target) : target 값을 초과하는 숫자가 배열 몇 번째에 있는지 탐색

 

석순과 종유석을 나눠서 배열에 저장, 정렬

1 ~ N 까지의 높이에 대해 포함되는 개수를 확인(종유석의 경우 N-v를 초과해야 벌레가 부딪침)

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int N, H;
int up[100001];
int down[100001];

int main() {
    cin >> N >> H;
    for (int i = 0; i < N / 2; i++) {
        cin >> down[i] >> up[i];
    }

    sort(up, up + (N / 2));
    sort(down, down + (N / 2));
    
    int res = 987654321;
    int cnt = 0;
    for (int i = 1; i <= H; i++) {
        int val1 =(N/2) - (lower_bound(down, down + (N / 2), i) - down); //해당 위치에 포함되는 석순의 수
        int val2 = (N/2) - (upper_bound(up, up + (N / 2), (H - i)) - up);//해당 위치에 포함되는 종유석의 수
        int val = val1 + val2;
        
        if (val < res) {
            res = val;
            cnt = 1;
        }
        else if (val == res) {
            cnt++;
        }
    }
    cout << res << ' ' << cnt;
    return 0;
}

이진 탐색을 사용하지 않고 단순 누적합을 이용하면 시간이 더 줄어 들거라 생각해서 풀어봄

위의 풀이와 비슷하지만 위의 배열은 입력받은 순으로 높이를 저장, 아래 코드는 해당 높이에 해당하는 석순/종유석의 개수

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
int N, H;
int up[500001];
int down[500001];

int main() {
    cin >> N >> H;
    int height;
    for (int i = 0; i < N; i++) {
        cin >> height;
        if (i % 2 == 0)
            down[height]++;
        else
            up[height]++;
    }

    int downSum = 0;
    for (int i = 1; i <= H; i++) {
        downSum += down[i];
    }

    int upAdd = up[H];
    int downAdd = down[1];
    int MIN = downSum + upAdd;//높이가 1일때 포함되는 석순과 종유석의 개수
    int cnt = 1;
    for (int i = 2; i <= H; i++) {
        upAdd += up[H - i + 1];//높이가 올라갈수록 포함되는 석순은 증가하기 때문에 누적
        //종유석의 경우 높이가 올라갈수록 포함되는 갯수가 줄어들것이기 때문에 종유석 총 갯수에서 빼기
        int val= (downSum - downAdd) + upAdd;
        
        if (val < MIN) {
            MIN = val;
            cnt = 1;
        }
        else if(val == MIN){
            cnt++;
        }
        downAdd += down[i];
    }
    
    cout << MIN << ' ' << cnt;
    return 0;
}

배열의 인덱스가 높이가 되버리기 때문에 메모리가 커질것은 예상(2800KB->5928KB)

시간이 줄어들기는 했지만 O(H x log(N/2)) 에서 O(H)로 변경된 만큼의 큰 차이라고는 느껴지지 않음(128ms->108ms)

 

'알고리즘' 카테고리의 다른 글

BOJ 12100 - 2048(Easy)(C++)  (0) 2021.09.02
BOJ 12015 - 가장 긴 증가하는 부분 수열2(C++)  (0) 2021.09.02
BOJ 19236 - 청소년 상어(C++)  (0) 2021.09.01
BOJ 15684 - 사다리 조작(C++)  (0) 2021.08.31
BOJ 1946 - 신입 사원(C++)  (0) 2021.08.27

댓글