题意:给出24个数字,按题目给出的旋转规律,是否能变成题目给出的目标序列,打印旋转的步骤。
题解:普通的bfs会超时,借鉴了别人的,当做练手写了个双向的bfs + 哈希,因为只有一个目标状态,所以循环之前从目标状态开始逆向搜8层,然后开始从输入序列开始正向搜索,要么正向搜不到八层就达到目标状态,或者中途和之前逆向已经搜到的某个状态重合时就是可以在16步内,注意输出逆向的时候步骤也需要改变,1对3、2对4。
#include <stdio.h>
#include <string.h>
const int MAXSIZE = 100000;
typedef int State[24];
const State tar = {0, 3, 4, 3, 0, 5, 6, 5, 0, 1, 2, 1, 0, 7, 8, 7, 0, 9, 10, 9, 0, 1, 2, 1};
struct ST {
State sta;
int order[10];
}que[2][MAXSIZE];
State st;
int head[2][MAXSIZE], next[2][MAXSIZE], dist[2][MAXSIZE];
int flag, pre, over;
void rotation(int dire, int s, int k) {
ST& temp = que[s][k];
if (dire == 1) {
int a = temp.sta[10];
int b = temp.sta[11];
for (int i = 11; i >= 2; i--)
temp.sta[i] = temp.sta[i - 2];
temp.sta[0] = a;
temp.sta[1] = b;
temp.sta[21] = temp.sta[9];
temp.sta[22] = temp.sta[10];
temp.sta[23] = temp.sta[11];
}
else if (dire == 2) {
int a = temp.sta[12];
int b = temp.sta[13];
for (int i = 12; i < 22; i++)
temp.sta[i] = temp.sta[i + 2];
temp.sta[22] = a;
temp.sta[23] = b;
temp.sta[9] = temp.sta[21];
temp.sta[10] = temp.sta[22];
temp.sta[11] = temp.sta[23];
}
else if (dire == 3) {
int a = temp.sta[0];
int b = temp.sta[1];
for (int i = 0; i < 10; i++)
temp.sta[i] = temp.sta[i + 2];
temp.sta[10] = a;
temp.sta[11] = b;
temp.sta[21] = temp.sta[9];
temp.sta[22] = temp.sta[10];
temp.sta[23] = temp.sta[11];
}
else {
int a = temp.sta[22];
int b = temp.sta[23];
for (int i = 23; i >= 12; i--)
temp.sta[i] = temp.sta[i - 2];
temp.sta[12] = a;
temp.sta[13] = b;
temp.sta[9] = temp.sta[21];
temp.sta[10] = temp.sta[22];
temp.sta[11] = temp.sta[23];
}
}
int hash(ST temp) {
int v = 0;
for (int i = 0; i < 24; i++)
v = v * 5 + temp.sta[i];
return v % MAXSIZE;
}
int try_insert(int cur, int k, int s) {
int h = hash(que[k][cur]);
int u = head[s][h];
while (u) {
if (memcmp(que[s][u].sta, que[k][cur].sta, sizeof(que[k][cur].sta)) == 0) {
if (k + s == 1) {
flag = 1;
pre = u;
return 1;
}
else
return 0;
}
u = next[s][u];
}
if (s == k) {
next[s][cur] = head[s][h];
head[s][h] = cur;
return 1;
}
return 0;
}
void bfs(int s) {
int front = 1, rear = 2;
memset(head[s], 0, sizeof(head[s]));
memcpy(que[s][front].sta, st, sizeof(st));
dist[s][front] = 0;
try_insert(front, s, s);
while (front < rear) {
ST& st1 = que[s][front];
if (dist[s][front] > 8)
return;
if (try_insert(front, s, 1 - s)) {
over = front;
return;
}
for (int i = 1; i <= 4; i++) {
ST& temp = que[s][rear];
temp = st1;
dist[s][rear] = dist[s][front] + 1;
rotation(i, s, rear);
temp.order[dist[s][front]] = i;
if (try_insert(rear, s, 1 - s)) {
over = rear;
return;
}
if (try_insert(rear, s, s))
rear++;
}
front++;
}
}
int main() {
memcpy(st, tar, sizeof(tar));
bfs(0);
const int cor[5] = {0, 3, 4, 1, 2};
int t;
scanf("%d", &t);
while (t--) {
flag = pre = over = 0;
for (int i = 0; i < 24; i++)
scanf("%d", &st[i]);
bfs(1);
if (flag && dist[0][pre] + dist[1][over] <= 16 ) {
if (dist[0][pre] + dist[1][over]) {
for (int i = 0; i < dist[1][over] ; i++)
printf("%d", que[1][over].order[i]);
for (int i = dist[0][pre] - 1; i >= 0; i--)
printf("%d", cor[que[0][pre].order[i]]);
printf("\n");
}
else
printf("PUZZLE ALREADY SOLVED\n");
}
else
printf("NO SOLUTION WAS FOUND IN 16 STEPS\n");
}
return 0;
}