16986번: 인싸들의 가위바위보
두 사람이 같은 손동작을 내어 무승부가 발생할 경우 경기 진행 순서상 뒤인 사람이 이긴 것으로 간주함에 다시 한 번 유의한다. 구체적으로, 경기 진행 순서는 지우, 경희, 민호 순으로 고정되
www.acmicpc.net
문제
혹시 마지막으로 엠티를 간 것이 언제인가? 엠티를 안간지 꽤 오래됐다면 요즘 유행하는 인싸들의 가위바위보를 모를 것이다. 요즘 인싸들은 엠티에서 평범한 가위바위보를 시시하다는 이유로 더 이상 취급하지 않는다. 대신 가위불바위총번개악마용물공기보스펀지늑대나무사람뱀을 한다. 이 게임의 명칭이 다소 긴 관계로 문제 내에서는 전체 명칭을 적는 대신 이 게임의 또 다른 이름인 인싸 가위바위보로 부르겠다. 인싸 가위바위보는 평범한 가위바위보와 같이 각 손동작간의 상성이 정해져있다.

인싸 가위바위보는 평범한 가위바위보보다 흥미진진하고 재밌지만 3명 이상이 경기를 할 때 누가 이기고 누가 졌는지를 빠르게 알기 힘들다는 단점이 있다. 그렇기에 3명 이상의 사람들 사이에서 인싸 가위바위보를 할 때는 모두가 동시에 경기를 진행하는 대신 일대일 경기를 여러 번 진행해 누가 우승했는지 판단한다. 3명이서 인싸 가위바위보를 할 때의 우승자를 정하기 위한 구체적인 방식은 아래와 같다. 편의상 참가자 3명을 A, B, C라고 하자.
- A, B, C는 게임 시작 전 우승을 위해 필요한 승수와 경기 진행 순서를 미리 합의한다. 경기 진행 순서가 A, B, C라고 가정하자.
- 먼저 A와 B가 경기를 진행해 승자를 결정한다. 만약 두 사람이 같은 손동작을 내어 무승부가 발생할 경우 경기 진행 순서상 뒤인 사람이 이긴 것으로 간주한다. 즉 A와 B가 같은 손동작을 내면 B의 승리, A와 C가 같은 손동작을 내면 C의 승리, B와 C가 같은 손동작을 내면 C의 승리이다.
- 이전 경기의 승자와 이전 경기에 참여하지 않은 사람이 경기를 진행해 승자를 결정한다.
- 특정 사람이 미리 합의된 승수를 달성할 때 까지 3을 반복한다.
- 합의된 승수를 최초로 달성한 사람이 우승한다.
밑의 표는 침, 펄, 풍 세 사람이 인싸 가위바위보를 진행하는 예시이다. 우승을 위해 필요한 승수는 3승이고 침, 펄, 풍 순서로 경기를 진행한다.

인싸 가위바위보 결과 풍이 제일 먼저 3승에 도달했으므로 우승자는 풍이다. 1라운드, 3라운드에서 두 사람이 같은 손동작을 냈을 때 경기 진행 순서상 뒤인 사람이 승리하는 것을 확인할 수 있다.
컴퓨터공학과 새내기 지우는 첫 엠티에서 친구 경희, 민호와 인싸 가위바위보를 할 생각에 굉장히 신나있다. 지우는 경희와 민호의 행동 패턴을 빅데이터로 분석해 인싸 가위바위보를 하는 중 경희와 민호의 차례가 왔을 때 이들이 낼 손동작의 순서를 정확히 알고 있다. 그래서 마음만 먹으면 전승 우승이 가능하지만 경기를 흥미진진하게 이끌기 위해 인싸 가위바위보를 할 때 모든 손동작을 다르게 내고 싶어한다. 지우의 즐거운 대학생활을 위해 인싸 가위바위보의 상성표와 경희, 민호가 낼 손동작의 순서가 주어졌을 때 지우가 모든 손동작을 다르게 내어 우승할 수 있는지 판단하는 프로그램을 만들자. 경기 진행 순서는 지우, 경희, 민호 순으로 정해져있다.
입력
첫째 줄에 인싸 가위바위보의 손동작 수를 나타내는 N(1 ≤ N ≤ 9)과 우승을 위해 필요한 승수 K(1 ≤ K ≤ 6)가 한 칸의 빈칸을 사이에 두고 주어진다.
그 다음 N개의 줄에 대해 상성에 대한 정보 $A_{i,j}$가 주어진다. i+1번째 줄에는 N개의 정수 $A_{i,1}$, $A_{i,2}$, $A_{i,3}$, ..., $A_{i,N}$이 한 칸의 빈칸을 사이에 두고 주어진다. $A_{i,j}$가 2일 경우에는 i번 손동작이 j번 손동작을 이긴다는 의미이고, 1일 경우에는 비긴다는 의미이고, 0일 경우에는 진다는 의미이다. $A_{i,i}$ = 1이고, i ≠ j일 때 $A_{i,j}$ ≠ 1임이 보장된다. 또한 $A_{i,j}$가 2일 경우에는 $A_{j,i}$가 0이고, $A_{i,j}$가 0일 경우에는 $A_{j,i}$가 2임이 보장된다.
그 다음 줄에는 경희가 앞으로 자신이 참여하는 20경기에서 낼 손동작의 순서가 한 칸의 빈칸을 사이에 두고 주어진다. 손동작의 번호는 1 이상 N 이하이다.
그 다음 줄에는 민호가 앞으로 자신이 참여하는 20경기에서 낼 손동작의 순서가 한 칸의 빈칸을 사이에 두고 주어진다. 마찬가지로 손동작의 번호는 1 이상 N 이하이다.
출력
첫째 줄에 지우, 경희, 민호 순으로 경기를 진행할 때 지우가 모든 손동작을 다르게 내어 우승할 수 있으면 1을, 그렇지 않으면 0을 출력한다.
코드
from itertools import permutations
n, k = map(int, input().split())
arr = [[0]*(n+1) for _ in range(n+1)]
for i in range(1, n+1):
input_data = list(map(int, input().split()))
for j in range(1, n+1):
arr[i][j] = input_data[j-1]
kh = list(map(int, input().split()))
mh = list(map(int, input().split()))
def dfs(p1, p2, idx, rsp, win):
if win[0] == k: # 지우 우승
return True
if win[1] == k or win[2] == k: # 민호 또는 경희 우승
return False
if idx[0] == n: # 지우가 모든 손동작을 사용해도 우승자가 안 나옴
return False
if p1 > p2:
p1, p2 = p2, p1
p3 = 3 - (p1 + p2) # 이번 경기에 참여하지 않은 사람
if arr[rsp[p1][idx[p1]]][rsp[p2][idx[p2]]] == 2: # p1 승
win[p1] += 1
idx[p1] += 1
idx[p2] += 1
return dfs(p1, p3, idx, rsp, win)
else: # p2 승
win[p2] += 1
idx[p1] += 1
idx[p2] += 1
return dfs(p2, p3, idx, rsp, win)
for jw in permutations(range(1, n+1)):
rsp = [list(jw), kh, mh] # 손동작 순서 배열
idx = [0] * 3 # 각 참여자들이 낼 손동작 배열의 인덱스
win = [0] * 3 # 각 참여자들이 이긴 횟수
if dfs(0, 1, idx, rsp, win):
print(1)
exit()
print(0)
지우가 낼 수 있는 모든 경우의 수를 순열로 만들어서 dfs 함수를 실행한다.
dfs 함수는 우승자가 나오거나 지우가 모든 손동작을 사용해도 우승자가 나오지 않는 경우 더이상 진행되지 않도록 리턴한다.
'문제풀이 > 백트래킹' 카테고리의 다른 글
[Python/파이썬] 백준 1038번 감소하는 수 (0) | 2023.10.18 |
---|---|
[Python/파이썬] 백준 6443번 애너그램 (0) | 2023.09.23 |
[Python/파이썬] 백준 9944번 NxM 보드 완주하기 (0) | 2023.07.13 |
[Python/파이썬] 백준 16987번 계란으로 계란치기 (0) | 2023.05.05 |
[Python/파이썬] 백준 14888번 연산자 끼워넣기 (0) | 2023.05.04 |
16986번: 인싸들의 가위바위보
두 사람이 같은 손동작을 내어 무승부가 발생할 경우 경기 진행 순서상 뒤인 사람이 이긴 것으로 간주함에 다시 한 번 유의한다. 구체적으로, 경기 진행 순서는 지우, 경희, 민호 순으로 고정되
www.acmicpc.net
문제
혹시 마지막으로 엠티를 간 것이 언제인가? 엠티를 안간지 꽤 오래됐다면 요즘 유행하는 인싸들의 가위바위보를 모를 것이다. 요즘 인싸들은 엠티에서 평범한 가위바위보를 시시하다는 이유로 더 이상 취급하지 않는다. 대신 가위불바위총번개악마용물공기보스펀지늑대나무사람뱀을 한다. 이 게임의 명칭이 다소 긴 관계로 문제 내에서는 전체 명칭을 적는 대신 이 게임의 또 다른 이름인 인싸 가위바위보로 부르겠다. 인싸 가위바위보는 평범한 가위바위보와 같이 각 손동작간의 상성이 정해져있다.

인싸 가위바위보는 평범한 가위바위보보다 흥미진진하고 재밌지만 3명 이상이 경기를 할 때 누가 이기고 누가 졌는지를 빠르게 알기 힘들다는 단점이 있다. 그렇기에 3명 이상의 사람들 사이에서 인싸 가위바위보를 할 때는 모두가 동시에 경기를 진행하는 대신 일대일 경기를 여러 번 진행해 누가 우승했는지 판단한다. 3명이서 인싸 가위바위보를 할 때의 우승자를 정하기 위한 구체적인 방식은 아래와 같다. 편의상 참가자 3명을 A, B, C라고 하자.
- A, B, C는 게임 시작 전 우승을 위해 필요한 승수와 경기 진행 순서를 미리 합의한다. 경기 진행 순서가 A, B, C라고 가정하자.
- 먼저 A와 B가 경기를 진행해 승자를 결정한다. 만약 두 사람이 같은 손동작을 내어 무승부가 발생할 경우 경기 진행 순서상 뒤인 사람이 이긴 것으로 간주한다. 즉 A와 B가 같은 손동작을 내면 B의 승리, A와 C가 같은 손동작을 내면 C의 승리, B와 C가 같은 손동작을 내면 C의 승리이다.
- 이전 경기의 승자와 이전 경기에 참여하지 않은 사람이 경기를 진행해 승자를 결정한다.
- 특정 사람이 미리 합의된 승수를 달성할 때 까지 3을 반복한다.
- 합의된 승수를 최초로 달성한 사람이 우승한다.
밑의 표는 침, 펄, 풍 세 사람이 인싸 가위바위보를 진행하는 예시이다. 우승을 위해 필요한 승수는 3승이고 침, 펄, 풍 순서로 경기를 진행한다.

인싸 가위바위보 결과 풍이 제일 먼저 3승에 도달했으므로 우승자는 풍이다. 1라운드, 3라운드에서 두 사람이 같은 손동작을 냈을 때 경기 진행 순서상 뒤인 사람이 승리하는 것을 확인할 수 있다.
컴퓨터공학과 새내기 지우는 첫 엠티에서 친구 경희, 민호와 인싸 가위바위보를 할 생각에 굉장히 신나있다. 지우는 경희와 민호의 행동 패턴을 빅데이터로 분석해 인싸 가위바위보를 하는 중 경희와 민호의 차례가 왔을 때 이들이 낼 손동작의 순서를 정확히 알고 있다. 그래서 마음만 먹으면 전승 우승이 가능하지만 경기를 흥미진진하게 이끌기 위해 인싸 가위바위보를 할 때 모든 손동작을 다르게 내고 싶어한다. 지우의 즐거운 대학생활을 위해 인싸 가위바위보의 상성표와 경희, 민호가 낼 손동작의 순서가 주어졌을 때 지우가 모든 손동작을 다르게 내어 우승할 수 있는지 판단하는 프로그램을 만들자. 경기 진행 순서는 지우, 경희, 민호 순으로 정해져있다.
입력
첫째 줄에 인싸 가위바위보의 손동작 수를 나타내는 N(1 ≤ N ≤ 9)과 우승을 위해 필요한 승수 K(1 ≤ K ≤ 6)가 한 칸의 빈칸을 사이에 두고 주어진다.
그 다음 N개의 줄에 대해 상성에 대한 정보 $A_{i,j}$가 주어진다. i+1번째 줄에는 N개의 정수 $A_{i,1}$, $A_{i,2}$, $A_{i,3}$, ..., $A_{i,N}$이 한 칸의 빈칸을 사이에 두고 주어진다. $A_{i,j}$가 2일 경우에는 i번 손동작이 j번 손동작을 이긴다는 의미이고, 1일 경우에는 비긴다는 의미이고, 0일 경우에는 진다는 의미이다. $A_{i,i}$ = 1이고, i ≠ j일 때 $A_{i,j}$ ≠ 1임이 보장된다. 또한 $A_{i,j}$가 2일 경우에는 $A_{j,i}$가 0이고, $A_{i,j}$가 0일 경우에는 $A_{j,i}$가 2임이 보장된다.
그 다음 줄에는 경희가 앞으로 자신이 참여하는 20경기에서 낼 손동작의 순서가 한 칸의 빈칸을 사이에 두고 주어진다. 손동작의 번호는 1 이상 N 이하이다.
그 다음 줄에는 민호가 앞으로 자신이 참여하는 20경기에서 낼 손동작의 순서가 한 칸의 빈칸을 사이에 두고 주어진다. 마찬가지로 손동작의 번호는 1 이상 N 이하이다.
출력
첫째 줄에 지우, 경희, 민호 순으로 경기를 진행할 때 지우가 모든 손동작을 다르게 내어 우승할 수 있으면 1을, 그렇지 않으면 0을 출력한다.
코드
from itertools import permutations n, k = map(int, input().split()) arr = [[0]*(n+1) for _ in range(n+1)] for i in range(1, n+1): input_data = list(map(int, input().split())) for j in range(1, n+1): arr[i][j] = input_data[j-1] kh = list(map(int, input().split())) mh = list(map(int, input().split())) def dfs(p1, p2, idx, rsp, win): if win[0] == k: # 지우 우승 return True if win[1] == k or win[2] == k: # 민호 또는 경희 우승 return False if idx[0] == n: # 지우가 모든 손동작을 사용해도 우승자가 안 나옴 return False if p1 > p2: p1, p2 = p2, p1 p3 = 3 - (p1 + p2) # 이번 경기에 참여하지 않은 사람 if arr[rsp[p1][idx[p1]]][rsp[p2][idx[p2]]] == 2: # p1 승 win[p1] += 1 idx[p1] += 1 idx[p2] += 1 return dfs(p1, p3, idx, rsp, win) else: # p2 승 win[p2] += 1 idx[p1] += 1 idx[p2] += 1 return dfs(p2, p3, idx, rsp, win) for jw in permutations(range(1, n+1)): rsp = [list(jw), kh, mh] # 손동작 순서 배열 idx = [0] * 3 # 각 참여자들이 낼 손동작 배열의 인덱스 win = [0] * 3 # 각 참여자들이 이긴 횟수 if dfs(0, 1, idx, rsp, win): print(1) exit() print(0)
지우가 낼 수 있는 모든 경우의 수를 순열로 만들어서 dfs 함수를 실행한다.
dfs 함수는 우승자가 나오거나 지우가 모든 손동작을 사용해도 우승자가 나오지 않는 경우 더이상 진행되지 않도록 리턴한다.
'문제풀이 > 백트래킹' 카테고리의 다른 글
[Python/파이썬] 백준 1038번 감소하는 수 (0) | 2023.10.18 |
---|---|
[Python/파이썬] 백준 6443번 애너그램 (0) | 2023.09.23 |
[Python/파이썬] 백준 9944번 NxM 보드 완주하기 (0) | 2023.07.13 |
[Python/파이썬] 백준 16987번 계란으로 계란치기 (0) | 2023.05.05 |
[Python/파이썬] 백준 14888번 연산자 끼워넣기 (0) | 2023.05.04 |