반응형
문제 링크: https://www.acmicpc.net/problem/7682
 

7682번: 틱택토

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 줄은 9개의 문자를 포함하며, 'X', 'O', '.' 중 하나이다. '.'은 빈칸을 의미하며, 9개의 문자는 게임판에서 제일 윗 줄 왼쪽부터의 순서이다. 입

www.acmicpc.net

<문제 풀이> DFS, 순열, 백트랙킹 알고리즘

 

각 테스트 케이스에 대해서 해당 케이스가 가능한 틱택토 경우의 수인지 판단하는 방법은 9개의 위치에 토큰을 놓는 순열을 구하면 됩니다.

 

9개의 위치에 토큰을 놓는 순열을 구하면 경우의 수는 9! = 362880입니다

가능한 순열을 state[362880][3][3] 배열에 하나씩 저장하고 테스트 케이스가 이 배열 안에 존재하는 지만 판단하면 끝입니다.

 

DFS로 모든 순열을 구할 때 두 가지 매개 변수가 필요합니다.

1. k : DFS 깊이를 추적하기 위함 -> k = 9가 되는 경우는 게임판을 모두 채운 경우입니다.

2. nextToken :  X, O 토큰을 번갈아가면서 놓기 위함

 

DFS의 base case는 게임이 끝날 때 즉, k = 9가 되거나 가로, 세로, 대각선 방향으로 3칸을 잇는 데 한 토큰만을 사용한 경우입니다.

 

가로, 세로, 대각선 방향으로 3칸을 잇는 경우 종료하는 조건이 있으니깐 실제로는 9! 보다 더 적은 경우의 수가 나옵니다.

 

 

 

 

<C++소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
 
int state[362880][3][3];
char board[3][3];
int cnt = 0;
 
 
bool isGameDone(int k) { 
    if (board[0][0!= '.' && board[0][0== board[1][1&& board[1][1== board[2][2]) return true// 대각선
    else if (board[2][0!= '.' && board[2][0== board[1][1&& board[1][1== board[0][2]) return true// 대각선
    else if (board[0][0!= '.' && board[0][0== board[0][1&& board[0][1== board[0][2]) return true// 나머지 가로 세로 
    else if (board[1][0!= '.' && board[1][0== board[1][1&& board[1][1== board[1][2]) return true;
    else if (board[2][0!= '.' && board[2][0== board[2][1&& board[2][1== board[2][2]) return true;
    else if (board[0][0!= '.' && board[0][0== board[1][0&& board[1][0== board[2][0]) return true;
    else if (board[0][1!= '.' && board[0][1== board[1][1&& board[1][1== board[2][1]) return true;
    else if (board[0][2!= '.' && board[0][2== board[1][2&& board[1][2== board[2][2]) return true;
    else if (k == 9return true// 판이 가득 찬 경우 
    else return false// 그 외 게임을 계속할 수 있다.
}
 
//nextToken = 'X' or 'O'
void dfs(int k, char nextToken) {
    if (isGameDone(k)) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                state[cnt][i][j] = board[i][j];
            }
        }
        cnt++;
        return;
    }
 
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (board[i][j] != '.'continue// 이미 토큰이 있으면 무시
            board[i][j] = nextToken;
            if (nextToken == 'O') dfs(k + 1'X'); //현재 위치에 토큰을 놓았을 때 다음 위치는 다른 토큰을 놓아야한다.
            else if (nextToken == 'X') dfs(k + 1'O');
            board[i][j] = '.'//모든 순열을 구하기 위해, 이미 구한 경우의 수는 제거
        }
    }
 
}
 
 
//가능한 조합인지 확인
bool isValid() {
    for (int k = 0; k < 362880; k++) {
        int ret = true;
        for (int i = 0; i < 3; i++) {
            if (!ret) break;
            for (int j = 0; j < 3; j++) {
                if (!ret) break;
                if (board[i][j] != state[k][i][j]) {
                    ret = false;
                    break;
                }
            }
        }
        if (ret) return true;
    }
    return false;
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
 
    fill(&board[0][0], &board[2][3], '.');
    dfs(0'X');
 
    while (true) {
        string s; cin >> s;
        if (s == "end"break;
        int index = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                board[i][j] = s[index++];
            }
        }
        if (isValid()) cout << "valid\n";
        else cout << "invalid\n";
    }
    cout << cnt;
    return 0;
 
 
 
}
cs
 
반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 1765번] 닭싸움 팀 정하기  (0) 2023.03.24
[백준 16235번] 나무 재테크  (0) 2023.03.23
[백준 2015번] 수들의 합4  (0) 2023.02.27
[백준 1083번] 소트  (0) 2023.02.26
[백준 1071번] 소트  (0) 2023.02.25

+ Recent posts