3x3칸 크기의 보드를 1자로 펼치면 000 000 000 의 형태가 나온다. 각 칸의 상태를 */. 을 0/1로 표현하면 29 가지 상태가 있다.
각 칸의 인접한 동서남북과 자신을 표현하면 아래와 같다.
int click[9]={
416, //110 100 000
464, //111 010 000
200, //011 001 000
308, //100 110 100
186, //010 111 010
89, //001 011 001
38, //000 100 110
23, //000 010 111
11, //000 001 011
};
그리고 이 값을 XOR하면 그 칸을 선택하여 십자로 뒤집은 결과가 된다. 예를 들어, 101 000 010 의 가장 왼쪽 위칸을 십자로 뒤집으면 010 010 010 인데, 이건 101 000 010 XOR 111 010 000 이다.
너비 우선 탐색을 사용하여 000 000 000 부터 0~8번째 칸을 하나씩 뒤집어보면서 주어진 보드의 상태와 같아질 때 뒤집은 횟수를 출력하면 된다.
#include <bits/stdc++.h>
using namespace std;
typedef long long lld;
int click[9]={
416, //110 100 000
464, //111 010 000
200, //011 001 000
308, //100 110 100
186, //010 111 010
89, //001 011 001
38, //000 100 110
23, //000 010 111
11, //000 001 011
};
int answer(int n){
queue<int> q;
int dist=0;
bool visit[1<<9]={};
q.push(0);
visit[0] = true;
while(!q.empty()){
int qs = q.size();
while(qs--){
int cur = q.front();
q.pop();
if(cur == n) return dist;
for(int i=0; i<9; ++i){
int next = cur^click[i];
if(!visit[next]){
q.push(next);
visit[next] = true;
}
}
}
++dist;
}
return dist;
}
int main(){
int i, T;
scanf("%d ", &T);
while(T--){
char s[10]={};
for(i=0; i<3; ++i) scanf("%s", s+3*i);
int board = 0;
for(i=0; i<9; ++i) board |= ((s[i]=='*')<<(8-i));
printf("%d\n", answer(board));
}
return 0;
}
댓글 없음:
댓글 쓰기