ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python 3] BOJ - 3430 "용이 산다"
    BOJ 2021. 11. 29. 19:41

     # 문제 링크

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

     

    3430번: 용이 산다

    옛날 아주 먼 옛날, 한 마을에 용이 살고 있었습니다. 그 마을에는 호수가 여러개 있었는데, 그 호수들은 모두 물이 들어 있었습니다. 이 마을에는 가끔 비가 내립니다. 신기하게도 비는 한 호수

    www.acmicpc.net

     

     # 풀이

     개인적으로 이 문제의 핵심은 그리디 알고리즘과 우선순위 큐라고 생각한다. 현재 호수를 마실 수 있는 차례라면, 1차적으로는 비지 않은 호수 중 하나를 마실 수 있다. 그런데, 그런 호수들 중에서 앞으로 비가 가장 먼저 올 호수를 비우는 것이 이득임은 자명하다. 따라서, 현재 호수를 마실 수 있다면, 비어 있는 호수들을 확인해야 한다

     그런데 문제에서 호수의 갯수가 백만개, 날씨의 정보 역시 길이가 백만이므로 모든 호수를 보는 $O(N^2)$의 풀이로는 절대로 시간안에 정답을 도출할 수 없다. 그러나 윗 단락에서 언급하였듯, 용이 호수를 마시는 순간이 온다면 필요한 정보는 마실 수 있는, 즉 비어있지 않는 호수 중 비가 오는 시간이 가장 빠른 호수이다. 따라서, 우선순위 큐가 필요하다.

    <그림 1. 우선순위 큐를 채우는 방법>

     위 그림 1은 임의의 상황을 나타낸 그림이다. 만일, 현재 i번째 인덱스까지 재앙이 일어나지 않는다고 가정하자. 따라서, 현재 i번째 인덱스에 따라 호수 3이 현재 비어있다는 뜻이다. 그런데, 현재 i번째 인덱스에 의해 호수 3은 채워진다. 이 때 i+1번째 인덱스는 다시 용이 호수 중 하나를 마실 수 있는 순간이다. 그런데 만일 i번째에서 우선순위 큐에 대한 처리가 이루어지지 않는다면, i+1번째 인덱스의 입장에서는 마실 수 있는 후보군을 하나 놓치는 것과 마찬가지이다. 따라서, 현재 상태가 비가 오는 상태이면서 비가 오는 호수가 비어져 있다면, 즉 현재 호수에 비가 와도 재앙이 발생하지 않는 경우라면 현재 호수가 다음에 비가 올 시간을 우선순위 큐에 저장해야 한다. 

     위와 같이 우선순위 큐를 채우게 된다면, 자연스럽게 용이 호수를 마시는 순간에 우선순위 큐에 들어가 있는 원소는 무조건 용이 호수를 마시는 시간보다 늦기 때문에 마실 수 있는 호수가 된다. 또한 비가 와서 현재 호수를 채우기 때문에 비어있는 호수를 용이 마시는 경우도 없다. 이 때, 각 호수를 기준으로 각자의 비오는 시간을 전처리해준다면 $O(NlogN)$만에 정답을 구할 수 있다

     

     # 코드

    import sys, heapq
    
    # 입력부
    tc = int(sys.stdin.readline())
    for _ in range(tc):
        n, m = map(int, sys.stdin.readline().split())
        arr = list(map(int, sys.stdin.readline().split()))
        
        # empty : 현재 호수가 비었는지 아닌지를 저장하는 리스트
        empty = [False] * (n + 1)
        # can : 재앙을 피할 수 있는지 없는지 나타내는 flag 변수
        can = True
        # cache : 현재 호수 번호가 i일 때, 비가 오는 시간을 역순으로 저장하는 2차원 배열
        cache = [[] for _ in range(n + 1)]
        # time : 현재 시간 i에서 비가 올 때 해당하는 호수의 번호
        time = [-1] * m
        for i in range(m - 1, -1, -1):
            if arr[i]:
                time[i] = arr[i]
                cache[arr[i]].append(i)
                
        # 가장 첫 시간을 우선순위 큐에 삽입
        q = []
        for i in range(1, n + 1):
            if cache[i]:
                heapq.heappush(q, cache[i].pop())
                
        # ans : 용이 마시는 호수 번호를 저장하는 리스트
        ans = []
        for i in range(m):
            # 현재 비가 온다면
            if arr[i]:
                # 비가 오는데 호수가 비지 않으면 재앙이 일어남
                if not empty[arr[i]]:
                    can = False
                    break
                # 비가 오는데 호수가 비었다면 그 다음 비오는 시간을 우선순위 큐에 저장
                empty[arr[i]] = False
                if cache[arr[i]]:
                    heapq.heappush(q, cache[arr[i]].pop())
                    
            # 비가 오지 않는다면
            else:
                # 마실 수 있는 호수가 있다면 그리디하게 마신다
                if q:
                    now = q[0]
                    heapq.heappop(q)
                    ans.append(time[now])
                    empty[time[now]] = True
                # 마실 수 있는 호수가 없으니 0을 저장한다
                else:
                    ans.append(0)
                    
        # 정답 출력
        if not can:
            print('NO')
        else:
            print('YES')
            print(' '.join(map(str, ans)))

    'BOJ' 카테고리의 다른 글

    [Python 3] BOJ - 13308 "주유소"  (0) 2021.12.04
    [Python 3] BOJ - 17182 "우주 탐사선"  (0) 2021.11.30
    [Python 3] BOJ - 16565 "N포커"  (0) 2021.11.21
    [Python 3] BOJ - 2478 "자물쇠"  (0) 2021.11.17
    [Python 3] BOJ - 20530 "양분"  (0) 2021.11.14

    댓글

Designed by Tistory.