2022. 12. 24. 21:51ㆍBaekjoon/Gold
https://www.acmicpc.net/problem/14867
14867번: 물통
표준 입력으로 물통 A의 용량을 나타내는 정수 a(1 ≤ a < 100,000), 물통 B의 용량을 나타내는 정수 b(a < b ≤ 100,000), 최종 상태에서 물통 A에 남겨야 하는 물의 용량을 나타내는 정수 c(0 ≤ c ≤ a), 최
www.acmicpc.net
문제 설명
문제
용량이 다른 두 개의 빈 물통 A, B가 있다. 이 물통들에 물을 채우고 비우는 일을 반복하여 두 물통을 원하는 상태(목표하는 양의 물을 담은 상태)가 되도록 만들고자 한다. 물통 이외에는 물의 양을 정확히 잴 수 있는 방법이 없으며, 가능한 작업은 다음과 같은 세 종류가 전부이다.
- [F(x): Fill x]: 물통 x에 물을 가득 채운다. (물을 채우기 전에 물통 x가 비어있는지 여부는 관계없음. 다른 물통은 그대로 둠)
- [E(x): Empty x]: 물통 x의 물을 모두 버린다. (다른 물통은 그대로 둠)
- [M(x,y): Move water from x to y)]: 물통 x의 물을 물통 y에 붓는다. 이때 만약 물통 x에 남아 있는 물의 양이 물통 y에 남아 있는 빈 공간보다 적거나 같다면 물통 x의 물을 물통 y에 모두 붓는다. 만약 물통 x에 남아 있는 물의 양이 물통 y에 남아 있는 빈 공간보다 많다면 부을 수 있는 만큼 최대로 부어 물통 y를 꽉 채우고 나머지는 물통 x에 남긴다.
예를 들어, 물통 A와 B의 용량이 각각 2리터와 5리터라고 하자. 두 물통 모두 빈 상태에서 시작하여 최종적으로 물통 A에는 2리터, 물통 B에는 4리터 물을 남기길 원할 경우, 다음과 같은 순서로 작업을 수행하면 총 8회의 작업으로 원하는 상태에 도달할 수 있다.
(0,0)→[F(B)]→(0,5)→[M(B,A)]→(2,3)→[E(A)]→(0,3)→[M(B,A)]→(2,1)→[E(A)]→(0,1)→[M(B,A)]→(1,0)→[F(B)]→(1,5)→[M(B,A)]→(2,4)
하지만, 작업 순서를 아래와 같이 한다면 필요한 작업 총 수가 5회가 된다.
(0,0)→[F(A)]→(2,0)→[M(A,B)]→(0,2)→[F(A)]→(2,2)→[M(A,B)]→(0,4)→[F(A)]→(2,4)
두 물통의 용량과 원하는 최종 상태를 입력으로 받은 후, 두 물통이 비어 있는 상태에서 시작하여 최종 상태에 도달하기 위한 최소 작업 수를 구하는 프로그램을 작성하시오.
입력
표준 입력으로 물통 A의 용량을 나타내는 정수 a(1 ≤ a < 100,000), 물통 B의 용량을 나타내는 정수 b(a < b ≤ 100,000), 최종 상태에서 물통 A에 남겨야 하는 물의 용량을 나타내는 정수 c(0 ≤ c ≤ a), 최종 상태에서 물통 B에 남겨야 하는 물의 용량을 나타내는 정수 d(0 ≤ d ≤ b)가 공백으로 분리되어 한 줄에 주어진다.
출력
목표 상태에 도달하는 최소 작업 수를 나타내는 정수를 표준 출력으로 출력한다. 만약 목표 상태에 도달하는 방법이 없다면 –1을 출력한다.
서브태스크
1 | 9 | A 물통의 용량은 1리터 |
2 | 14 | B 물통의 용량은 A 물통의 용량의 배수 |
3 | 34 | 1 ≤ a, b ≤ 1,000 |
4 | 43 | 원래의 제약조건 이외에 아무 제약조건이 없다. |
예제 입력 1
3 7 3 2
예제 출력 1
9
예제 입력 2
2 5 0 1
예제 출력 2
5
예제 입력 3
3 5 2 4
예제 출력 3
-1
문제 풀이
import sys
from collections import deque
input = sys.stdin.readline
a, b, c, d = map(int, input().split())
def visit(q, visited, cnt, nx, ny):
if (nx, ny) not in visited:
q.append((cnt, nx, ny))
visited.add((nx, ny))
def bfs(x, y):
q = deque([(0, x, y)])
visited = set()
while q:
cnt, a_value, b_value = q.popleft()
if (a_value, b_value) == (c, d):
return cnt
nx, ny = a_value, 0 # Empty B
visit(q, visited, cnt+1, nx, ny)
nx, ny = 0, b_value # Empty A
visit(q, visited, cnt+1, nx, ny)
nx, ny = a_value, b
visit(q, visited, cnt+1, nx, ny)
nx, ny = a, b_value
visit(q, visited, cnt+1, nx, ny)
# B에서 A로 물 옮기기
if a_value + b_value < a:
nx, ny = a_value + b_value, 0
else:
nx, ny = a, a_value + b_value - a
visit(q, visited, cnt+1, nx, ny)
# A에서 B로 물 옮기기
if a_value + b_value < b:
nx, ny = 0, a_value + b_value
else:
nx, ny = a_value + b_value - b, b
visit(q, visited, cnt+1, nx, ny)
return -1
print(bfs(0, 0))
'Baekjoon > Gold' 카테고리의 다른 글
[Baekjoon] 치즈 / Python, 파이썬 / 2638 (0) | 2022.12.29 |
---|---|
[Baekjoon] 미로만들기 / Python, 파이썬 / 2665 (0) | 2022.12.27 |
[Baekjoon] 4연산 / Python, 파이썬 / 14395 (0) | 2022.12.22 |
[Baekjoon] 환승 / Python, 파이썬 / 5214 (0) | 2022.12.21 |
[Baekjoon] 이분 그래프 / Python, 파이썬 / 1707 (0) | 2022.12.21 |