알고리즘/문제 풀이

4600번: 정글의 법칙

Themion 2021. 12. 22. 14:10

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

 

4600번: 정글의 법칙

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 음수 -B와 양수 P가 주어진다. B는 다리의 수이고, P는 사람의 수이다. B와 P는 20을 넘지 않는다. (B가 음수로 주

www.acmicpc.net

각 나무에서 다리를 지나가는 사람과 다리가 비면 지나갈 사람 두 종류로 나누자. while문으로 무한 반복을 시키면서, 빈 다리가 있는 지역에 다리가 비었을 때 지나갈 사람이 있을 경우, 가능한 한 많은 사람을 다리에 넣은 뒤 일정 시간이 지나면 다리를 건넌 것으로 간주한다. 또 아직 사람이 건너고 있는 다리가 있는 경우, 반복문을 통해 여러 번 접근할 것이므로 시간을 1 감소한 것으로 간주한다. 이 과정을 마지막 다리를 건넌 사람이 P명이 될 때까지 반복하면 된다.

#include <cstdio>

#define MAX_B 20

// 각 다리, 혹은 다리와 다리 사이의 지점
// time: 이동하는 데에 걸리는/남은 시간
// moving: 이동 가능한 최대 인원/이동중인 인원
// pending: 0/이동 대기중인 인원
struct Bridge { public: int time = 0, moving = 0, pending = 0; };

int min(int a, int b) { return a < b ? a : b; }

int test_case(int B, int P){
    // time: 모든 인원이 다리를 건너는 데 걸리는 시간
    // group: 각 다리를 건널 수 있는 그룹의 최대 인원
    int time = 0, group;
    // bridge[i]: i번째 다리, place: 다리로 이어진 지점
    Bridge bridge[MAX_B], place[MAX_B + 1];

    // 문제의 조건을 입력받은 뒤
    for (int i = 0; i < B; i++) 
        scanf("%d %d", &(bridge[i].moving), &(bridge[i].time));

    // 모든 인원을 첫 지점에 대기시킨다
    place[0].pending = P;

    // 모든 인원이 이동할 때까지
    while (place[B].pending < P) {
        // 시간을 1씩 소모하며 각 다리/지점의 상황을 변화시킨다
        time++;

        // 각 다리에 대해 역순으로 순회
        for (int b = B - 1; b >= 0; b--) {
            // 다리를 건너는 그룹이 없을 때
            if (!place[b].time && place[b].pending) {
                // 건널 수 있는 사람의 최대치를 계산
                group = min(place[b].pending, bridge[b].moving);
                // 최대한 많이 사람을 pending에서 moving으로 보낸다
                place[b].pending -= group;
                place[b].moving = group;
                // 이동에 걸리는 시간을 초기화
                place[b].time = bridge[b].time;
            }
            // 이동에 걸리는 시간 계산
            if (place[b].time) place[b].time -= 1;
            if (!place[b].time && place[b].moving) {
                // 이동을 마친 인원을 다음 지역의 pending으로 보낸 뒤
                place[b + 1].pending += place[b].moving;
                // 이동을 마친 지점의 moving을 비운다
                place[b].moving = 0;
            }
        }
    }

    // 모든 인원
    return time;
}

int main() {
    int B, P;
    // 각 테스트 케이스를 실행
    while (scanf("%d %d", &B, &P) && P)
        printf("%d\n", test_case(-B, P));

    return 0;
}

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

4889번: 안정적인 문자열  (0) 2021.12.22
4673번: 셀프 넘버  (0) 2021.12.22
4386번: 별자리 만들기  (0) 2021.12.22
4344번: 평균은 넘겠지  (0) 2021.12.22
4307번: 개미  (0) 2021.12.22