题意:9张正方形卡片摆成3*3,每张卡片有图案,求从当前状态旋转到目标状态的最短步。卡片的某些边类似齿轮,如果相邻的边都是齿轮边,它们就会同时旋转。
思路:搜索。这个题比较复杂,涉及到好多问题,比如状态的编码解码,图像相同的校验,旋转的模拟等等。首先编码问题用9位4进制数表示,我因为编码解码写错WA了好多发。。图像相同的校验暴力解决,注意可能出现对称的情况,即多个相同态。旋转的模拟用dfs(bfs超时),搜索哪些卡片会被带动,根据与原卡片的曼哈顿距离的奇偶性确定旋转方向。
程序的主体当然是BFS,因为需要求最短步,里面套一下上述功能就可以了。
#include<iostream>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
#define INF 100000000
char G[10][10][10];
char G2[10][10][10];
bool st[10][4];
int match[10][4]; //哪些状态可看作终态
int dis[266666]; //存每个状态与初态距离
//判断是否为终态
bool judge(int s){
for(int t=8;t>=0;t--){
int cur=s%4;
s/=4;
if(!match[t][cur])return 0;
}
return 1;
}
bool r[9];
int s[9];
bool dfs(int cur){
if(cur>2){//上
if(!r[cur-3])if(st[cur][(5-s[cur])%4]&&st[cur-3][(3-s[cur-3])%4]){
r[cur-3]=1;
dfs(cur-3);
}
}
if(cur<6){//下
if(!r[cur+3])if(st[cur][(3-s[cur])%4]&&st[cur+3][(5-s[cur+3])%4]){
r[cur+3]=1;
dfs(cur+3);
}
}
if(cur%3!=0){//左
if(!r[cur-1])if(st[cur][(4-s[cur])%4]&&st[cur-1][(6-s[cur-1])%4]){
r[cur-1]=1;
dfs(cur-1);
}
}
if(cur%3!=2){//右
if(!r[cur+1])if(st[cur][(6-s[cur])%4]&&st[cur+1][(4-s[cur+1])%4]){
r[cur+1]=1;
dfs(cur+1);
}
}
}
//旋转函数,返回旋转后状态
int rota(int x,int t){
memset(r,0,sizeof(r));
int tmp=x;
for(int i=8;i>=0;i--){
s[i]=tmp%4;
tmp/=4;
}
r[t]=1;
dfs(t);
int re=0;
for(int i=0;i<9;i++){
if(!r[i])continue;
if(abs(t-i)&1){
s[i]+=3;
}else{
s[i]++;
}
s[i]%=4;
}
for(int i=0;i<9;i++){
re*=4;
re+=s[i];
}
return re;
}
int main(){
int t;
cin>>t;
while(t--){
//init
memset(dis,0,sizeof(dis));
memset(match,0,sizeof(match));
//input
for(int i=0;i<3;i++){
for(int k=0;k<8;k++){
for(int j=0;j<3;j++){
scanf("%s",G[i*3+j][k]);
}
}
}
for(int i=0;i<3;i++){
for(int k=0;k<8;k++){
for(int j=0;j<3;j++){
scanf("%s",G2[i*3+j][k]);
}
}
}
//
for(int i=0;i<9;i++){
for(int j=0;j<4;j++){
scanf("%d",&st[i][j]);
}
}
//
bool ok;
bool hasans=1;
int ans=INF;
for(int k=0;k<9;k++){
//0
ok=1;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if(G[k][i][j]!=G2[k][i][j])ok=0;
}
}
if(ok)match[k][0]=1;
//90
ok=1;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if(G[k][7-j][i]!=G2[k][i][j])ok=0;
}
}
if(ok)match[k][1]=1;
//180
ok=1;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if(G[k][7-i][7-j]!=G2[k][i][j])ok=0;
}
}
if(ok)match[k][2]=1;
//270
ok=1;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if(G[k][j][7-i]!=G2[k][i][j])ok=0;
}
}
if(ok)match[k][3]=1;
if(match[k][0]+match[k][1]+match[k][2]+match[k][3]==0){
hasans=0;break;
}
}
if(!hasans){
cout<<-1<<endl;
continue;
}
queue<int> que; que.push(0); dis[0]=1;
if(judge(0)){
cout<<0<<endl;
continue;
}
while(!que.empty()){
int cur=que.front(); que.pop();
for(int i=0;i<9;i++){
int news=rota(cur,i);
if(!dis[news]){
dis[news]=dis[cur]+1;
if(judge(news)){
ans=dis[cur];
break;
}
que.push(news);
}
}
if(ans!=INF)break;
}
if(ans==INF){
cout<<-1<<endl;
}else{
cout<<ans<<endl;
}
}
return 0;
}