본문 바로가기
Algorithm/Baekjoon

2251. 물통 (Python)

by 원만사 2022. 6. 16.
반응형

 

 

2251번: 물통

각각 부피가 A, B, C(1≤A, B, C≤200) 리터인 세 개의 물통이 있다. 처음에는 앞의 두 물통은 비어 있고, 세 번째 물통은 가득(C 리터) 차 있다. 이제 어떤 물통에 들어있는 물을 다른 물통으로 쏟아 부

www.acmicpc.net

 

풀이

 BFS를 통해서 from 물통에서 to 물통으로 물을 쏟아 부은 후 A 물통과 C 물통의 물의 양을 살펴본다. 큐에는 리스트의 형태로 '[A 물통의 물의 양, B 물통의 물의 양, C 물통의 물의 양]'으로 값을 넣어 줬다.

 

 큐에 중복된 경우를 넣지 않게 하기 위해 물의 양들을 문자열로 만들고 이를 딕셔너리의 키로 사용하여 체크해줬다. 예를 들어 A, B, C에 각각 4, 3, 22 리터의 물이 들어있다면 문자열로 '4 3 22'와 같이 중간에 빈 문자를 삽입하여 문자열을 만들어주고 딕셔너리에 해당 문자열을 키로 하는 값이 있는지를 체크한다.

# 각 물통의 물의 양으로 방문 체크 딕셔너리에서 키로 사용될 문자열 생성
def setKey(arr):
    return str(arr[0]) + " " + str(arr[1]) + " " + str(arr[2])

 

 위와 같은 방법으로 중복되는 경우를 제외하고 BFS를 통해서 문제의 답을 구할 수 있다.

 

코드

from collections import deque
from collections import defaultdict
from copy import deepcopy


# 각 물통의 물의 양으로 방문 체크 딕셔너리에서 키로 사용될 문자열 생성
def setKey(arr):
    return str(arr[0]) + " " + str(arr[1]) + " " + str(arr[2])


# from 물통에서 to 물통으로 물을 쏟아 붓는 함수
# from 물통 번호, to 물통 번호, from 물통에 들어있는 물의 양, to 물통에 들어있는 물의 양
# return 값 : 물을 부은 후 from 물통의 물의 양, to 물통의 물의 양
def pourWater(toBucket, fromLiter, toLiter):
    toMaxLiter = buckets[toBucket]  # to 물통의 부피
    toRemain = toMaxLiter - toLiter  # to 물통의 남은 부피

    # to 물통의 남은 부피가 from 물통의 물의 양 이하일 때는 물을 쏟아 부으면
    # from 물통에는 to 물통의 남은 부피만큼의 물이 사라지고 to 물통은 가득 차게 된다.
    if toRemain <= fromLiter:
        return fromLiter - toRemain, toMaxLiter
    else:  # 반대의 경우는 from 물통의 물이 모두 to 물통으로 옮겨진다.
        return 0, toLiter + fromLiter


if __name__ == '__main__':
    buckets = list(map(int, input().split()))
    q = deque()
    res = set()  # A 물통의 물의 양이 0일 때, C 물통의 물의 양 -> 중복을 피하기 위해 셋으로 받는다.
    visitedDict = defaultdict(bool)  # 방문 체크 딕셔너리

    q.append([0, 0, buckets[2]])  # (A 물통의 물의 양, B 물통의 물의 양, C 물통의 물의 양)
    visitedDict[setKey([0, 0, buckets[2]])] = True

    while q:
        nowBuckets = q.popleft()

        if nowBuckets[0] == 0:  # A 물통의 물의 양이 0이면 res에 C 물통의 물의 양을 기록
            res.add(nowBuckets[2])

        for i in range(3):  # from 물통 번호
            if nowBuckets[i] == 0:  # from 물통이 비어 있으면 탐색하지 않음
                continue

            for j in range(3):  # to 물통 번호
                if i == j:  # 두 물통이 같은 경우는 continue
                    continue

                tmpBuckets = deepcopy(nowBuckets)  # 각 물통의 물의 양을 기록하는 임시 리스트
                fromBucket, toBucket = pourWater(j, nowBuckets[i], nowBuckets[j])  # 물을 부은 후 남은 물의 양
                tmpBuckets[i], tmpBuckets[j] = fromBucket, toBucket  # tmpBuckets에 바뀐 물의 양 기록
                dictKey = setKey(tmpBuckets)  # 바뀐 물의 양을 기준으로 key 생성

                if not visitedDict[dictKey]:  # 이전에 체크하지 않은 경우 큐에 넣어주고 방문 체크
                    q.append(tmpBuckets)
                    visitedDict[dictKey] = True

    resList = sorted(list(res))
    print(*resList)

 

반응형

'Algorithm > Baekjoon' 카테고리의 다른 글

2629. 양팔저울 (Python)  (0) 2022.06.18
13905. 세부 (Python)  (0) 2022.06.17
17612. 쇼핑몰 (Python)  (0) 2022.06.14
17616. 등수 찾기 (Python)  (0) 2022.06.13
4811. 알약 (Python)  (0) 2022.06.13

댓글