분류: 시뮬레이션, 완전 탐색 /
문제
문제 설명
혹시 마지막으로 엠티를 간 것이 언제인가? 엠티를 안간지 꽤 오래됐다면 요즘 유행하는 인싸들의 가위바위보를 모를 것이다. 요즘 인싸들은 엠티에서 평범한 가위바위보를 시시하다는 이유로 더 이상 취급하지 않는다. 대신 가위불바위총번개악마용물공기보스펀지늑대나무사람뱀을 한다. 이 게임의 명칭이 다소 긴 관계로 문제 내에서는 전체 명칭을 적는 대신 이 게임의 또 다른 이름인 인싸 가위바위보로 부르겠다. 인싸 가위바위보는 평범한 가위바위보와 같이 각 손동작간의 상성이 정해져있다.
인싸 가위바위보는 평범한 가위바위보보다 흥미진진하고 재밌지만 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개의 줄에 대해 상성에 대한 정보 Ai,j가 주어진다. i+1번째 줄에는 N개의 정수 Ai,1, Ai,2, Ai,3, ..., Ai,N이 한 칸의 빈칸을 사이에 두고 주어진다. Ai,j가 2일 경우에는 i번 손동작이 j번 손동작을 이긴다는 의미이고, 1일 경우에는 비긴다는 의미이고, 0일 경우에는 진다는 의미이다. Ai,i = 1이고, i ≠ j일 때 Ai,j ≠ 1임이 보장된다. 또한 Ai,j가 2일 경우에는 Aj,i가 0이고, Ai,j가 0일 경우에는 Aj,i가 2임이 보장된다.
그 다음 줄에는 경희가 앞으로 자신이 참여하는 20경기에서 낼 손동작의 순서가 한 칸의 빈칸을 사이에 두고 주어진다. 손동작의 번호는 1 이상 N 이하이다.
그 다음 줄에는 민호가 앞으로 자신이 참여하는 20경기에서 낼 손동작의 순서가 한 칸의 빈칸을 사이에 두고 주어진다. 마찬가지로 손동작의 번호는 1 이상 N 이하이다.
출력
첫째 줄에 지우, 경희, 민호 순으로 경기를 진행할 때 지우가 모든 손동작을 다르게 내어 우승할 수 있으면 1을, 그렇지 않으면 0을 출력한다.
풀이
#include <iostream>
#include <algorithm>
using namespace std;
int N, K;
int A[10][10]; // 0: <, 1: =, 2: >
int hand[3][20]; // 0:나, 1: 경희, 2: 민호
int win[3], cursor[3], player[2];
inline int game() {
return A[hand[player[0]][cursor[player[0]]++]][hand[player[1]][cursor[player[1]]++]];
}
inline bool canPlay() {
if(player[0] == 0 and cursor[0] >= N) return false;
if(player[1] == 0 and cursor[0] >= N) return false;
if(cursor[player[0]] >= 20 or cursor[player[1]] >= 20) return false;
return true;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
cin >> N >> K;
for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) cin >> A[i][j];
for(int i=1; i<3; i++) for(int j=0; j<20; j++) cin >> hand[i][j];
if(K > N) {
cout << 0;
return 0;
}
for(int i=0; i<N; i++) hand[0][i] = i + 1;
do {
fill(win, win+3, 0);
fill(cursor, cursor+3, 0);
player[0] = 0; player[1] = 1;
while(canPlay()) {
int winnerIdx;
switch (game()) {
case 0: winnerIdx = 1; break;
case 1: winnerIdx = player[0] > player[1] ? 0 : 1; break;
case 2: winnerIdx = 0; break;
}
int winner = player[winnerIdx];
if(++win[winner] == K) break;
player[1] = 3 - winner - player[!winnerIdx]; // next player
player[0] = winner;
}
if(win[0] == K) break;
} while(next_permutation(hand[0], hand[0] + N));
cout << (win[0] == K);
}
나(지우)는 N번의 가위바위보 안에 이겨야한다. 지우가 N+1번의 가위바위보를 할 경우 한 번 이상 중복해서 같은 패를 내야한다.
따라서 지우가 최대로 가위바위보를 할 경우 N개의 패의 순서를 정하고 완전 탐색으로 직접 시뮬레이션을 돌리면된다.
위 풀이에 배열이 많아 각 인덱스의 의미를 설명하면 아래와 같다.
- `A[i][j]`: `i` vs `j`의 승자(문제에 나와있음)
- `hand[p][c]`: 사람 `p`(0, 1, 2 순서 대로 지우, 경희 민호)가 `c`번 째 내는 패 (1 ≤ `hand[p][c]` ≤ N)
- `win[p]`: 완전 탐색 중 하나의 경우의 수에서 사람 `p`가 이긴 횟수
- `cursor[p]`: 사람 `p`가 다음 가위바위보에서 낼 `hand[p][c]`에서 인덱스 `c`
- 0 ≤ `cursor[0]` < N, 0 ≤ `cursor[1]`, `cursor[2]` < 20
- `player[2]`: 가위바위보를 할 사람 두 명(`player[i] = p`)
얻어갈 만한 로직은 가위바위보를 진 사람을 교체하는 로직 정도 `next = 3 - winner - loser`
다음 가위바위보를 참여할 사람은 전체의 합(`3`)에서 참여한 사람 두 명(`winner`와 `loser`)을 빼면 얻을 수 있다.
'Problem Solving > BOJ' 카테고리의 다른 글
[백준 - 17070] 파이프 옮기기 1 - C++ (0) | 2024.04.07 |
---|---|
[백준 - 1799] 비숍 - C++, Python (0) | 2024.04.01 |
[백준 - 1189] 컴백홈 - C++ (0) | 2024.03.21 |
[백준 - 4991] 로봇 청소기 - C++ (0) | 2023.12.25 |
[백준 - 17244] 아맞다우산 - C++ (1) | 2023.12.25 |