题目: LINK
题目给出了 起始 和 最终的两张图, 每个图有9小块, 每个小块有对应图案,而且 每个小块的边有可能有齿轮
每一步是顺时针转动一个小块,对于和它相邻的小块,如果这两块接触的两条边都含有齿轮,就会带动相邻的小块转动,被带动的小块有可能会继续带动其他小块。
求 最少多少步可以由起始图 得到目的图.
BFS,不过有点繁琐。
要注意,1,状态的记录,不能把每个小块的图案压缩8*8*9,每次去判断,虽然没有这样试着去写,应该妥妥过不掉。每个小块有4种状态,即转动0,1,2,3次,对于9个小块 4^9个状态,可以接受。
2, 每次转动后, 每块的每条边也会跟着转动,也就是图中齿轮的情况会变化。
3, 每次判断是否可以达到目的图时,要判断当前每块的转动状态是否和目标一样。
代码写的比较挫。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
char S[11][10][10], T[11][10][10];
int t, nowv[4][4], dir[4][2]= {0, -1, -1, 0, 0, 1, 1, 0};
bool vv[4][4], vis[266666];
int G[11][5];
struct node {
int ddir[10], cut[10], step;
};
node SS, TT;
int get(int ddir[]) {//对于9个块的0123的状态进行压缩,看做4进制.
int ret = 0;
for(int i = 1; i <= 9; i++) {
ret <<= 2; ret |= ddir[i];
}
return ret;
}
int equ(node x, node y) {//判断当前的状态和目标状态是否吻合,即当前的转动位置是否吻合目标
for(int i = 1; i<= 9; i++) {
if((1<<(3 - x.ddir[i])) & y.ddir[i]) continue;
return 0;
}
return 1;
}
void dfs(int x,int y, int ad) {
nowv[x][y] = ad;
for(int i = 0; i < 4; i++) {
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(nx < 1 || nx > 3 || ny < 1 || ny > 3 || vv[nx][ny]) continue;
if(G[(x-1)*3 + y][i] == 0 || G[(nx - 1)*3 + ny][(i+2)%4] == 0) continue;
vv[nx][ny] = 1;
dfs(nx, ny, ad ==1 ? -1: 1);
}
}
void change(node &in, int x, int y) {
memset(vv, 0, sizeof(vv));
memset(nowv, 0, sizeof(nowv)); // maybe not change.
for(int i = 1; i <= 9; i++) {
for(int j = 0; j < 4; j++) {
int ww = (in.cut[i] >> j) & 1;
G[i][3-j] = ww; //获得当前 各块的每条边是否有齿轮
}
}
int xx = (x-1) / 3 + 1;
int yy = (x-1) % 3 + 1;
vv[xx][yy] = 1;
dfs(xx, yy, y); //搜索 确定9块是否是否转动
for(int i =1; i <= 3; i++) {//
for(int j = 1; j <= 3; j++) {
int id = (i-1)*3 + j;
in.ddir[id] = (in.ddir[id] + nowv[i][j]); //修改每块的转动后的新状态0123
if(in.ddir[id] == -1) in.ddir[id] = 3;
else if(in.ddir[id] == 4) in.ddir[id] = 0;
if(nowv[i][j] == 1) {//更新转动后每块每条边是否含有齿轮
int gg = in.cut[id] &1;
in.cut[id] >>= 1;
in.cut[id] |= (gg << 3);
}
else if(nowv[i][j] == -1) {
int gg = (in.cut[id] >> 3) &1;
in.cut[id] &= 7;
in.cut[id] <<= 1;
in.cut[id] |= gg;
}
}
}
}
int bfs() {
queue<node > Q;
memset(vis, 0, sizeof(vis));
for(int i = 1; i<=9; i++) SS.ddir[i] = 0;
SS.step = 0;
Q.push(SS);
vis[get(SS.ddir)] = 1;
node now, next;
while(!Q.empty()) {
now = Q.front(); Q.pop();
if(equ(now, TT)) return now.step;
for(int i = 1; i<= 9; i++) {
next = now;
next.step ++;
change(next, i, 1); //对于i-th块转动
int tmp = get(next.ddir);
if(vis[tmp]) continue;
vis[tmp] = 1;
Q.push(next);
}
}
return -1;
}
int gao(int x) {//一共四种旋转,得到可有哪些旋转得到,压缩到4位二进制里面 .
int ret = 0;
int flag = 0;
for(int i = 1; i <= 8; i++) {
for(int j = 1; j <= 8; j++) {
if(S[x][i][j] != T[x][i][j]) {
flag = 1; break;
}
}
if(flag ) break;
}
ret <<= 1;
if(!flag) ret |= 1;
flag = 0;
for(int i = 1; i <= 8; i++) {
for(int j = 1; j <= 8; j++) {
if(S[x][i][j] != T[x][j][9 - i]) {
flag = 1; break;
}
}
if(flag) break;
}
ret <<= 1;
if(!flag) ret |= 1;
flag = 0;
for(int i = 1; i <= 8; i++) {
for(int j = 1; j <= 8; j++) {
if(S[x][i][j] != T[x][9-i][9-j]) {
flag = 1; break;
}
}
if(flag) break;
}
ret <<= 1;
if(!flag) ret |= 1;
flag = 0;
for(int i = 1; i <= 8; i++) {
for(int j = 1; j <= 8; j++) {
if(S[x][i][j] != T[x][9-j][i]) {
flag = 1; break;
}
}
if(flag) break;
}
ret <<= 1;
if(!flag) ret |= 1;
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &t);
while(t--) {
for(int i = 1; i<=24; i++) {
for(int j = 1; j<=3; j++) {
int ii = (i-1)/8 ;
ii = ii*3 + j;
scanf("%s", S[ii][(i-1)%8 + 1]+1);
}
}
for(int i = 1; i <= 24; i++) {
for(int j = 1; j <= 3; j++) {
int ii = (i-1) / 8;
ii = ii* 3 + j;
scanf("%s", T[ii][(i-1)%8 + 1] + 1);
}
}
int tt;
for(int i = 1; i <= 9; i++) {
SS.cut[i] = 0;
for(int j = 0; j < 4; j++) {
scanf("%d", &tt);
SS.cut[i] <<= 1; SS.cut[i] |= tt;//把每一个小块4个边的状态记录
}
}
int mark = 0;
for(int i = 1; i <= 9 ; i++) {
TT.ddir[i] = gao(i); //求终态的每个块可以由起始状态怎样旋转得到.用4为二进制表示
if(TT.ddir[i] == 0) {
mark = 1; break;
}
}
if(mark) {
puts("-1"); continue;
}
int ans = bfs();
printf("%d\n", ans);
}
return 0;
}