본문 바로가기
Develop/백준 (Cpp)

[백준] 10472번 : 십자뒤집기 (C++)

by Tarra 2023. 8. 20.

10472번 : 십자뒤집기


문제)

당신에게 3x3 크기의 보드가 주어진다. 각각의 칸은 처음에 흰색 혹은 검은색이다. 만약 당신이 어떤 칸을 클릭한다면 당신이 클릭한 칸과 그 칸에 인접한 동서남북 네 칸이 (존재한다면) 검은색에서 흰색으로, 혹은 흰색에서 검은색으로 변할 것이다.

당신은 모든 칸이 흰색인 3x3 보드를 입력으로 주어지는 보드의 형태로 바꾸려고 한다. 보드를 회전시킬수는 없다.

 

 

 

입력 :

첫 줄에는 테스트 케이스의 숫자 P(0 < P ≤ 50)이 주어진다.

각각의 테스트 케이스에 대해서 세 줄에 걸쳐 한 줄에 세 글자씩이 입력으로 들어온다. "*"은 검은색을 뜻하며 "."은 흰색을 뜻한다.

 

 

 

출력 :

각각의 테스트 케이스에 대해서 흰 보드를 입력에 주어진 보드로 바꾸는 데 필요한 최소 클릭의 횟수를 구하여라.

 

 

 

 

 

 

풀이)

 

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <iostream>
#include <queue>
#include <vector>
#include <bitset>
#include <string>
 
 
using namespace std;
 
int p;
int visited[1000];
 
// 주어진 보드를 비트마스킹을 이용하여 10진수로 바꾸었다.
unsigned long convert(vector<string> vec)
{
    /*
    
    *..        100
    **.  => 110     =>  100110100 =>  308
    *..        100
    
    */
 
    string temp = "";
 
    for (auto nxt : vec)
    {
        temp += nxt;
    }
 
    bitset<9> bit(temp);
 
    return bit.to_ulong();
}
 
// 해당 버튼을 클릭했을 때 변화하는 배열
vector<string> tapping(int a, int b, vector<string> board)
{
    int dx[] = { 01-100 };
    int dy[] = { 000-11 };
 
    for (int i = 0; i < 5; i++)
    {
        int nx = a + dx[i];
        int ny = b + dy[i];
 
        if (0 > nx || nx >= 3continue;
        if (0 > ny || ny >= 3continue;
        
        if (board[nx][ny] == '0') board[nx][ny] = '1';
        else if (board[nx][ny] == '1') board[nx][ny] = '0';
    }
 
    return board;
}
 
 
int bfs(vector<string> goal)
{
    int t = 0;
    vector<string> start_board(3"000");
 
    queue<vector<string>> q;
    q.push(start_board);
    visited[convert(start_board)] = 1;
 
    while (!q.empty())
    {
        int loop = q.size();
        
        for (int _ = 0; _ < loop; _++)
        {
            vector<string> board = q.front();
            q.pop();
            
            // 목표하는 배열과 같다면 time를 리턴하면 됨.
            if (board == goal) return t;
 
            // 모든 버튼 클릭에 대하여 bfs를 진행한다.
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    vector<string> nxt = tapping(i, j, board);
                    int nxt_binary = convert(nxt);
 
                    if (!visited[nxt_binary])
                    {
                        q.push(nxt);
                        visited[nxt_binary] = 1;
                    }
                }
            }
        }
 
        t++;
    }
}
 
 
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
 
    cin >> p;
 
    for (int _ = 0; _ < p; _++)
    {
        vector<string> vec;
        fill(visited, visited + 10000);
 
        for (int i = 0; i < 3; i++)
        {
            string temp = "";
            char t;
            for (int j = 0; j < 3; j++)
            {    
                cin >> t;
                if (t == '*') temp += "1";
                else if (t == '.') temp += "0";
            }
            vec.push_back(temp);
        }
 
        cout << bfs(vec) << '\n';
    }
 
    return 0;
}
cs

출처 : https://www.acmicpc.net/problem/10472 

 

10472번: 십자뒤집기

당신에게 3x3 크기의 보드가 주어진다. 각각의 칸은 처음에 흰색 혹은 검은색이다. 만약 당신이 어떤 칸을 클릭한다면 당신이 클릭한 칸과 그 칸에 인접한 동서남북 네 칸이 (존재한다면) 검은색

www.acmicpc.net