필승 전략 게임 - 베스킨라빈스 31 게임에서 반드시 이길 수 있을까?
1. 베스킨라빈스 31
술게임에서 많이 하는 게임이다. 규칙은 다음과 같다.
두 사람이 게임을 하는데 1부터 시작해서 3개까지 숫자를 부를 수 있고
31을 먼저 부르면 지는 게임이다.
예를 들어 A가 1,2,3을 부르면 B는 4,5를 부르고 A는 다시 6,7을 부르고....
상대방이 나한테 선공을 양보했다.
술을 못마시는 나는 최대로 집중해서 이 게임에서 반드시 이기고 싶다.
어떻게 해야 내가 이 게임에서 반드시 이길 수 있을까?
2. 게임의 필승 전략1
결국 내가 게임을 이길려면 마지막에 30을 불러야 게임에서 이길 수 있게 된다.
그 전에 내가 불러야 하는 숫자는 얼마일까?
상대방이 27, 28, 29중 하나로 끝을 내야 내가 마지막에 30을 부를 수 있다
상대방이 27, 28, 29중 하나로 끝을 내게 만들려면 나는 26을 불러야한다.
그러면 계속해서, 내가 26을 부를려면 상대방이 몇을 불러야할까?
23, 24, 25중 하나를 불러야 내가 26을 부를 수 있게 된다.
그러면 상대방이 23, 24, 25중 하나를 부르게 할려면? 나는 22를 불러야한다.
이런식으로 반복한다면... 매 순간 내가 불러야하는 수는..
30, 26, 22, 18, 14, 10, 6, 2
따라서 처음에 내가 1, 2를 부른다면 나는 이 게임에서 반드시 이길 수 있다.
3. 연습문제
20004번: 베스킨라빈스 31 (acmicpc.net)
20004번: 베스킨라빈스 31
베스킨라빈스 게임은 1부터 31까지의 수를 순차적으로 한번에 1개 이상, 3개 이하 연달아 부를 수 있으며, 마지막 31을 부른 사람이 지는 게임이다. 시온이와 민우는 베스킨라빈스 게임을 하기로
www.acmicpc.net
4. 풀이
조금 더 응용해서, 1부터 N개 이하의 수를 부를 수 있다고 할 때, 후공인 내가 이길 수 있는 모든 N을 구해야하는 문제
위 사고 과정을 조금 응용해서..
선공인 사람이 30을 부르면 이길 수 있으므로,
30, 30-(N+1), 30-2*(N+1), ...을 부르면 선공인 사람이 게임에서 이길 수 있다.
예를 들어 N = 3라고 한다면..
30, 26, 22, 18, 14, 10, 6, 2를 부르면 게임에서 이길 수 있다.
따라서 선공인 사람이 최선의 전략으로 게임한다면 처음에 2를 부르면 게임에서 절대로 이길 수 없다.
그런데 예를 들어 N = 4라고 한다면..
30, 25, 20, 15, 10, 5, 0을 부르면 선공인 사람이 게임에서 이길 수 있다.
그런데 부를 수 있는 수는 1부터 시작하는데 처음에 부를 수 있는 수는 1,2,3,4까지 이다.
그러니까 5를 부를수가 없다.
이런 경우에는 최선의 전략으로 게임하는 두명에 대해 선공인 사람은 게임에서 이길 수가 없다.
후공이 5,10,15,20,25,30을 부를 수 있기 때문이다.
그러므로 30부터 (N+1)을 반복적으로 뺄때, 음수가 된 순간 다시 N+1을 더해본다.
그리고 얻은 수가 N보다 크다면 후공인 사람이 반드시 이길 수 있고, N보다 작거나 같다면 선공인 사람이 게임에서 이길 수 있다.
from sys import stdin
A = int(stdin.readline())
for n in range(1,A+1):
x = 30
while x > 0:
x -= (n+1)
x += (n+1)
if x > n:
print(n)
5. 베스킨라빈스 N
조금 더 일반적인 상황으로 확장해보자.
이번엔 N을 부르면 게임에서 진다.
그런데 부를 수 있는 수는 1부터 X 이하까지이다.
선공인 내가 최대로 집중하면 게임에서 반드시 이길 수 있을까?
그럴려면 처음에 어떤 수를 불러야할까?
6. 게임의 필승 전략2
그냥 N = 31을 N으로 바꿨을 뿐이고, X = 3을 X로 바꿨을 뿐이다.
마찬가지의 사고과정으로 전개해보자.
선공인 내가 게임에서 이길려면 N-1을 불러야한다.
계속해서 상대방은 N-2, N-3, ... , N-1-X 중 하나를 불러야 내가 N-1을 부를 수 있다.
그렇게 만들려면 그 전에 나는 N-1-(X+1)을 불러야한다.
반복적으로 이 게임에서 내가 반드시 이길려면...
N-1, N-1-(X+1), N-1-2*(X+1), ...을 불러야 게임에서 이길 수 있다.
베스킨라빈스 31게임에서는 N = 31이고 X = 3으로 이 경우 선공인 사람이 반드시 이길 수 있다.
하지만 N = 31이고 X를 임의의 수로 만드는 순간 위 문제에서도 알 수 있듯이 선공이 반드시 이기라는 보장이 없다.
마찬가지로 N과 X로 일반적으로 확장하는 순간 선공인 사람이 반드시 이기라는 보장은 없다.
7. 연습문제
25179번: 배스킨라빈스~N~귀엽고~깜찍하게~ (acmicpc.net)
25179번: 배스킨라빈스~N~귀엽고~깜찍하게~
준서가 주어진 $N, M$에 대해 이길 수 있다면 Can win을 출력하고, 이길 수 없다면 Can't win을 출력한다.
www.acmicpc.net
8. 풀이
N, M으로 확장한 베스킨라빈스 게임인데,
선공인 사람이 필승하는지 여부를 아는 방법으로
N-1, N-1-(M+1), N-1-2*(M+1),....을 구해봐서 이 안의 수를 부를 수 있는지를 체크해야한다고 했는데
즉, N-1에서 (M+1)을 반복적으로 빼서 음수가 되는 순간 M+1을 한번 더하고 그 수가 M보다 크다면 후공이 이기고
M보다 작거나 같다면 선공이 이기게 된다.
그런데 N과 M의 범위가 $10^{18}$으로 매우 크다.
최악의 경우 N이 $10^{18}$이고 M = 1이면 이렇게 반복적으로 빼다가는 1초안에 푸는건 절대로 불가능
사실 이를 극복하는 테크닉을 이미 배운적이 있다
https://deepdata.tistory.com/380
매우 큰 수를 나머지 연산으로 줄일 수 있는 마법(백준-개미)
1. 문제 https://www.acmicpc.net/problem/10158 10158번: 개미 가로 길이가 w이고 세로 길이가 h인 2차원 격자 공간이 있다. 이 격자는 아래 그림처럼 왼쪽 아래가 (0,0)이고 오른쪽 위가 (w,h)이다. 이 공간 안의
deepdata.tistory.com
https://deepdata.tistory.com/524
100번할 것을 1번만에 하는 나눗셈 연산 -시험 감독-
1. 문제 13458번: 시험 감독 (acmicpc.net) 13458번: 시험 감독 첫째 줄에 시험장의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 각 시험장에 있는 응시자의 수 Ai (1 ≤ Ai ≤ 1,000,000)가 주어진다. 셋
deepdata.tistory.com
반복적으로 빼는 대신에 나눗셈 연산 단 1번으로 이를 해결할 수 있다
구체적으로 N-1을 M+1로 나눈 나머지가 0이라면.. 게임을 이기기 위해 불러야하는 매직 넘버는
0, M+1, (M+2), ...로 시작하고
나머지가 r = 1~M이라면 게임을 이기기 위해 불러야하는 매직 넘버가
r, r+(M+1), ...
그러므로 선공인 내가 이길 수 있는지 알고 싶다면.. N-1을 M+1로 나눈 나머지를 구해서 0이라면 내가 이길 수 없고,
0이 아니라면 내가 이길 수 있으며, 선공에 그 나머지만큼을 부르면 된다.
from sys import stdin
n,m = map(int,stdin.readline().split())
if (n-1)%(m+1) >= 1:
print("Can win")
else:
print("Can't win")