본문 바로가기
Problem Solving

[Python][백준 2251] 물통

by tls1107 2024. 3. 19.
728x90
반응형

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

 

2251번: 물통

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

www.acmicpc.net


/*
신경써야 할 부분은 바로 :
1. 수통의 최대용량, 수통의 현재 채워진 용량 둘을 구분지어 활용
2. 물을 옮길때 수통이 가득차거나 빌 때까지 옮긴다
3. 도달했던 값은 방문처리로 재방문 방지
4. 결과값들을 정렬 후 출력

문제가 그리 어려워 보이진 않았지만 막상 풀려고 하니 멍해졌다
직접 얼마만큼의 물을 옮겨야 할지 먼저 계산해볼까 했지만 답이 없어보여서
그냥 두 가정 모두 실행해보고 수통의 물이 0보다 작거나 넘치면 리턴하는 식으로 설계했다
직관적으로 짜려고 했더니 dfs 를 12개나 써버렸다. 좀 더 잘 짠 사람의 코드가 궁금하다.
*/

import sys
input = sys.stdin.readline
 
def dfs(va,vb,vc) :
    # 오류값 확인 및 이미 방문한 경우 리턴
    if sum([va,vb,vc]) != c or (va,vb,vc) in check or va > a or vb > b or vc > c or va < 0 or vb < 0 or vc < 0:
        return
        
    if va == 0 and vc not in result :
        result.append(vc)
        
    check.append((va,vb,vc))
    
    # 물통이 바닥날 때까지 붓는 경우
    dfs(0,vb + va ,vc)
    dfs(0,vb ,vc+ va)
    dfs(va + vb,0,vc)
    dfs(va,0 ,vc+ vb)
    dfs(va,vb + vc,0)
    dfs(va + vc,vb ,0)
    
    # 물통이 가득찰 때까지 붓는 경우
    dfs(va - (b - vb),b,vc)
    dfs(va- (c - vc),vb,c)
    dfs(a,vb- (a - va),vc)
    dfs(va,vb- (c - vc),c)
    dfs(a,vb,vc- (a - va))
    dfs(va,b,vc- (b - vb))
 
a,b,c = map(int ,input().split())
vA,vB,vC = (0,0,c)
result = []
check = []

dfs(vA,vB,vC)

print(" ".join(list(map(str, sorted(result)))))

풀 때 어려웠던 점 또는 느낀점 :

공익 2일차 문제풀기 성공

매일 이렇게 풀면 소집해제까지 600개가 넘는 문제를 풀 수 있다.

소집해제 하면 PS 고수가 되어있을수도..? ㅎㅎ

 

문제를 다시 풀기 시작한지 얼마 안되어서 그런지

뇌가 아직 굳어있는게 느껴졌다. 그래도 어제보단 할만했다.

내일은 오늘보다 잘해야겠다.


참고할만한 다른 사람 코드 :

from collections import deque


def pour(x, y):
    if not visited[x][y]:
        visited[x][y] = 1
        q.append((x, y))


def bfs():
    q.append((0,0))  # 처음 물통 a,b는 0,0
    visited[0][0] = 1
    while q:
        x, y = q.popleft()
        z = c - x - y  # z는 a와b에 의해 결정된다.
        if x == 0:  # 조건에서 a물통이 0일때 이므로
            answer.append(z)

        # a에서 b 물을 옮기는 경우
        if x > 0 and y < b:  # a에 물이 있고 b에 물이 가득차있지 않을 때
            w = min(x, b - y)
            pour(x - w, y + w)
        # a에서 c
        if x > 0 and z < c:
            w = min(x, c - z)
            pour(x - w, y)

        # b에서 a
        if y > 0 and x < a:
            w = min(y, a - x)
            pour(x + w, y - w)
        # b에서 c
        if y > 0 and z < c:
            w = min(y, c - z)
            pour(x, y - w)

        # c에서 a
        if z > 0 and x < a:
            w = min(z, a - x)
            pour(x + w, y)
        # c에서 b
        if z > 0 and y < b:
            w = min(z, b - y)
            pour(x, y + w)


if __name__ == "__main__":
    a, b, c = map(int, input().split())
    # visited: a 물통과 b 물통의 양에 따라 c 물통의 양이 정해지기 때문에
    # a,b 두 통을 실행한 적이 있는지 확인하는 2중리스트
    visited = [[0] * (b + 1) for _ in range(a + 1)]
    # 답을 넣을 배열
    answer = []
    # BFS
    q = deque()
    bfs()
    # 답 출력
    answer.sort()
    print(' '.join(list(map(str, answer))))
    
    // 출처 : https://deok2kim.tistory.com/81

 

다른 사람들도 비슷하게 푼듯 하다 

내거보다 가독성이 좋고 나는 가득차거나 빌 때를 그냥 다 넣고 조건문으로 걸렀지만

위의 코드는 미리 min 함수를 통해 둘 중에 하나만 선택했다.

함수 사용을 줄일 수 있어 좋아보인다. 

또한 변수를 두개만 사용하는건 신기하다.

728x90
반응형

'Problem Solving' 카테고리의 다른 글

[Python][백준 1897] 토달기  (0) 2024.03.21
[Python][백준 1595] 북쪽나라의 도로  (0) 2024.03.20
[Python][백준 1068] 트리  (0) 2024.03.18
[C++][백준 1406] 에디터  (0) 2022.01.25
[C++] [백준 2783] 삼각 김밥  (0) 2021.08.09

댓글