题目大意:有一个彩色的两个轮子的拼盘,每次转动都是同颜色的一起转动。转动有四种,左边的顺时针,右边顺时针,左边逆时针,右边逆时针。
解题思路:刚开始用单向bfs,结果忽略了数组太大了,要4^16大小的数组,编译器开不下,所以改用了双向的bfs(),先逆向的bfs()一次,遍历步数只要到8就可以。以后每组数据再从正向开始bfs(),如果在步数不大于八的时候在逆向bfs()的记录里找到相同的状况的拼盘,就可以找到路径。所以步数不大于八的都找不到就找不到。
要注意:逆向的bfs()动作也要保存相反,还有步数不大于八的,不能第一次找到8就出来,要找完所有步数为八的。
#include<stdio.h>
#include<string.h>
#include<string>
#include<map>
using namespace std;
const int N = 24;
const int M = 1000000;
int n, tmp;
char st1[M][N], st2[M][N];
const char init[] = "034305650121078709:90121";
map<string, int> vis1;
map<string, int> vis2;
int dis1[M], dis2[M], fa1[M], fa2[M], step[M];
void LC(char *st){
int t1 = st[10];
int t2 = st[11];
int i;
for(i = 9; i >= 0; i--)
st[i + 2] = st[i];
st[0] = t1;
st[1] = t2;
for(i = 9; i < 12; i++)
st[i + 12] = st[i];
}
void RC(char *st){
int t1 = st[12];
int t2 = st[13];
int i;
for(i = 14; i < N; i++)
st[i - 2] = st[i];
st[22] = t1;
st[23] = t2;
for(i = 9; i < 12; i++)
st[i] = st[i + 12];
}
void LCC(char *st){
int t1 = st[0];
int t2 = st[1];
int i;
for(i = 2; i < 12; i++)
st[i - 2] = st[i];
st[10] = t1;
st[11] = t2;
for(i = 9; i < 12; i++)
st[i + 12] = st[i];
}
void RCC(char *st){
int t1 = st[22];
int t2 = st[23];
int i;
for(i = 21; i >= 12; i--)
st[i + 2] = st[i];
st[12] = t1;
st[13] = t2;
for(i = 9; i < 12; i++)
st[i] = st[i + 12];
}
int bfs(){
vis1.clear();
int front = 0, rear = 1;
memset(fa1, 0, sizeof(fa1));
vis1[st1[0]] = 1;
memset(step, 0, sizeof(step));
if(vis2[st1[front]])
return front;
while(front < rear){
if(step[front] >= 8){
front++;
continue;
}
for(int i = 0; i < 4; i++){
step[rear] = step[front] + 1;
memcpy(st1[rear], st1[front], sizeof(st1[front]));
if(i == 0)
LC(st1[rear]);
else if(i == 1)
RC(st1[rear]);
else if(i == 2)
LCC(st1[rear]);
else
RCC(st1[rear]);
if(vis1[st1[rear]] == 0){
vis1[st1[rear]] = 1;
dis1[rear] = i + 1;
fa1[rear] = front;
if(vis2[st1[rear]] != 0)
return rear;
rear++;
}
}
front++;
}
return -1;
}
void bfs_back(){
int front = 0, rear = 1;
memset(fa2, 0, sizeof(fa2));
memcpy(st2[front], init, sizeof(init));
memset(step, 0, sizeof(step));
vis2[st2[0]] = 1;
while(front < rear){
if(step[front] >= 8){
front++;
continue ;
}
for(int i = 0; i < 4; i++){
step[rear] = step[front] + 1;
memcpy(st2[rear], st2[front], sizeof(st2[front]));
if(i == 0)
LC(st2[rear]);
else if(i == 1)
RC(st2[rear]);
else if(i == 2)
LCC(st2[rear]);
else
RCC(st2[rear]);
if(vis2[st2[rear]] == 0){
vis2[st2[rear]] = rear;
switch(i + 1){
case 1: dis2[rear] = 3;break;
case 2: dis2[rear] = 4;break;
case 3: dis2[rear] = 1;break;
case 4: dis2[rear] = 2;
}
fa2[rear] = front;
rear++;
}
}
front++;
}
}
void print_path(int rear){
if(rear){
print_path(fa1[rear]);
printf("%d", dis1[rear]);
}
}
void print_back(int rear){
while(rear){
printf("%d", dis2[rear]);
rear = fa2[rear];
}
}
int main(){
scanf("%d", &n);
bfs_back();
while(n--){
for(int i = 0; i < N; i++){
scanf("%d", &tmp);
st1[0][i] = tmp + '0';
}
if(memcmp(init, st1[0], sizeof(init)) == 0){
printf("PUZZLE ALREADY SOLVED\n");
continue;
}
int c = bfs();
if(c == -1)
printf("NO SOLUTION WAS FOUND IN 16 STEPS\n");
else {
print_path(c);
print_back(vis2[st1[c]]);
printf("\n");
}
}
return 0;
}