23575 Squid Game
https://www.acmicpc.net/problem/23575
물통 1, 2, 3에 각각 물이 리터 들어있다. 에 대해, 리터의 물이 들어있는 물통 와 리터의 물이 들어있는 물통 을 선택하여, 물통 에 리터, 물통 에 리터의 물이 남도록 물통 에서 물통 로 물을 붓는 동작을 할 수 있다. 처음 물의 양 가 주어졌을 때, 1000번 이내의 동작으로 한 물통을 완전히 비우도록 하는 동작을 순서대로 출력하라. 물통 에서 물통 로 물을 붓는 동작을 와 같은 꼴로, 각 동작마다 개행하여 출력하면 된다.
힌트
개인적으로는 상세한 풀이를 참고하지 않고 풀어볼 수 있다면 충분히 재미있는 문제가 될 것이라고 생각하여 이 문제에 대해 비슷한 감상을 갖는 이를 위해 문단을 추가하였습니다.
힌트 1: 제시될 풀이의 방향
동작을 통해 물통에 든 물의 최솟값을 줄일 방법에 대해 생각할 것이다.힌트 2: 힌트 1의 상세
최대 30번 정도의 동작을 통해 최솟값을 2배 줄일 방법이 존재한다고 가정하면, $10^9 < 2^{30}$이므로, 대략 30번 정도의 이러한 동작 묶음을 통해 최솟값을 감소시켜 0으로 만들 수 있다.힌트 3: 풀이 요약
물을 붓는 동작을 사용하여 나눗셈을 구현하였다. 최대 30번 정도의 동작을 통해 $x \le y$에 대해 $x, y$리터의 물이 담긴 물통으로부터 $y % x$리터 또는 $(k * x - y) % x$리터의 물이 남은 물통을 만들 수 있다 ($k$는 $k * x - y$를 음이 아닌 정수로 만드는 임의의 수이다). $x, y$에 따라 둘 중 하나를 선택하여 최솟값이 2배 줄일 수 있다. $10^9 < 2^{30}$이므로, 대략 30번 정도의 이러한 동작 묶음을 통해 최솟값을 감소시켜 0으로 만들 수 있다.풀이
동작 묶음 구성
물통에 든 물의 양이 각각 리터라고 하자. 물통 1, 2, 3에 각각 물이 리터 들었을 때, 이도록 물통의 번호를 잘 바꾸자.
우선 를 크게 만들고 나서 시작하려고 한다. 가 성립하지 않는다면 물통 3에서 물통 2로 물을 부을 것이다. 각 물통에는 만큼의 물이 남는다. 인 경우 가 성립하는데, 아니라면 이고 이므로 이고 이는 모순이다. 이때 이므로, 물통들의 번호를 적절히 바꾸고 새로운 값에 변수를 다시 붙여, 물통 1, 2, 3에 각각 물이 리터 들었고, 와 를 만족한다고 가정하자.
다음으로 물통에 남은 물의 양 중 최솟값이 리터 또는 리터 이하가 되도록 만들 것이다. , 라고 하자. 이므로 이다. 인 경우를 예시로 들어 어떤 전략을 취하여야 할지 생각하여 볼 것이다.
- 인 경우, 는 보다 작거나 같다. 이 경우에는 물통 2에서 물통 1로 물을 부었을 때 물통 2에 물이 리터 남는다.
- 인 경우, 는 보다 작거나 같다. 이 경우에는 물통 3에서 물통 1로 물을 부은 후, 물통 1에서 물통 2로 물을 부었을 때 물통 1에 물이 리터 남는다.
각 경우는 와 를 비교하여 구별할 수 있다. 인 경우에 비슷한 결과를 만들 수 있는지 탐색하자.
우선, 가 보다 작거나 같다고 가정하자.
- 일 때, 물통 3에서 물통 1으로 물을 부을 것이다. 물통 1, 2에 각각 물이 리터 남는데, 이다.
- 일 때, 물통 2에서 물통 1으로 물을 부을 것이다. 물통 1, 2에 각각 물이 리터 남는데, 이다.
위 과정 이후 에 를 대입하고, 인 동안 위 과정을 반복한다. 물통 3에 물이 충분히 있으므로 위 과정은 잘 동작한다. 이 되었을 때 전술한 동작을 통해 물통 2에 물을 리터 남길 수 있다.
이 보다 크거나 같다고 가정하자. 새로운 과정을 소개하기 전에, 위 과정을 분석하여 보자. 위 과정은 물통 2에 리터를 남기게 된다. 이 과정은 직관적으로는 다음과 같이 이해할 수 있다:
- 두 물통의 물 차이가 리터가 될 때까지 물을 잘 옮긴다.
- 마지막 동작을 통해 차이를 실현한다.
그러니 이번에는 다음과 같이 과정을 설계할 수 있을 것이다:
- 두 물통의 물 차이가 리터가 될 때까지 물을 잘 옮긴다.
- 마지막 동작을 통해 차이를 실현한다.
따라서 대신 를 초기값으로 주어 위 과정을 반복하고, 마지막 동작에서 물통 1에서 물통 2로 물을 부어 물통 1에 리터를 남길 수 있다.
위 동작 묶음을 수행하였을 때, 남아있는 물의 양 중 최솟값이 기존 최솟값의 보다 작거나 같게 된다. 최솟값을 줄이는 위의 과정을 동작 묶음이라고 부르자. 동작 묶음이 수행될 때마다 물의 양의 최솟값이 줄어들게 되므로, 동작 묶음을 유한하게 많이 사용하여 물통 하나를 비울 수 있다. 따라서 위 동작 묶음에 따라 동작을 나열하는 해답의 정당성이 증명된다.
분석: 동작 횟수
그러나 이 문제는 단지 동작을 나열할 뿐이 아니라, 동작의 횟수가 1000회로 제한되어 있다. 따라서 위 풀이를 검증하기 위해서는 동작의 정당성 뿐만 아니라 횟수에 대해서도 추가적인 분석이 필요하다.
풀이에 서술된 동작 묶음에 동작이 최대 몇 개 포함되었는지 분석하여 보자.
- 를 가정하기 위해 최대 1회
- . 회.
따라서 각 동작 묶음 당 최대 31회의 동작을 수행한다. 초기 최솟값은 이므로, 최솟값을 절반씩 줄이는 경우 동작 묶음을 최대 31회 사용한다. 따라서 위 풀이는 동작을 최대 회 사용한다. 이는 문제의 조건과 일치한다.
대부분의 경우 1000회보다 훨씬 적은 횟수로 해답이 나올 것 같지만 적당한 분석을 수행할 수 없었다.
계산 복잡도
시간이 아주 오래 걸리지는 않는다. 각 수행마다 , 정도만 살피면 되기 때문이다. 시간 0ms으로 동작하는 해 또한 구성할 수 있다.
문제의 조건이 으로 주어졌을 때, 위 분석을 사용하면 답의 크기는 정도일 것으로 추측한다.