題目:如題目給出的圖形(下面給出),可以執行四種操作:左邊的圓形順時針旋轉,右邊的圓形順時針旋轉,
左邊的圓形逆時針旋轉,右邊的圓形逆時針旋轉;問嫩否從給定狀態在16步內走到初始狀態(如下圖)。
分析:圖論,搜索,雙向廣搜。這裡使用雙向bfs求解,利用map判重即可。
如果使用bfs結果會很大導致TLE和MLE;
首先,利用已知狀態,搜索八層(兩萬多個節點),將結果存到隊列和map中;
然後,利用最終狀態反向搜索,如果超過八層,沒有發現相遇的節點,即不可能超過;
如果發現存在第一次搜索的結果,則找到答案(本次的結果要逆向輸出)。
說明:注意輸出最小的數字串(同一個方向旋轉三次和反向轉三次等價)。
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <map>
using namespace std;
int ans[21] = {0, 3, 4, 3, 0, 5, 6, 5, 0, 1, 2, 1, 0, 7, 8, 7, 0, 9, 10, 9, 0};
int match(int string1[], int string2[])
{
for (int i = 0; i < 21; ++ i) {
if (string1[i] != string2[i]) {
return false;
}
}
return true;
}
int rotation_buf[21];
int rotation_maps[4][21] = {
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 12, 13, 14, 15, 16, 17, 18, 19, 20,
0, 1, 2, 3, 4, 5, 6, 7, 8, 19, 20, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20,
0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 9, 10};
void wheel_rotation(int id, int data[])
{
for (int i = 0; i < 21; ++ i) {
rotation_buf[i] = data[i];
}
for (int i = 0; i < 21; ++ i) {
data[rotation_maps[id][i]] = rotation_buf[i];
}
}
class qnode
{
public:
int steps;
char state[22];
char operate[10];
qnode(){}
qnode(int data[], int Steps) {
steps = Steps;
for (int i = 0; i < 21; ++ i) {
state[i] = data[i]+'0';
}
state[21] = 0;
for (int i = 0; i < 10; ++ i) {
operate[i] = 0;
}
}
};
qnode Q1[30000];
map<string, int> M1;
int bfs1(int data[], int ans[])
{
M1.clear();
int move = 1, save = 1;
qnode now(data, 0);
M1[now.state] = save;
Q1[save ++] = now;
while (move < save) {
now = Q1[move ++];
if (now.steps > 8) {
return 0;
}
for (int i = 0; i < 4; ++ i) {
for (int j = 0; j < 21; ++ j) {
data[j] = now.state[j]-'0';
}
wheel_rotation(i, data);
qnode New(data, now.steps+1);
if (!M1[New.state]) {
M1[New.state] = save;
strcpy(New.operate, now.operate);
New.operate[now.steps] = i+'1';
Q1[save ++] = New;
if (match(data, ans)) {
puts(New.operate);
return 1;
}
}
}
}
return 0;
}
qnode Q2[30000];
map<string, int> M2;
int bfs2(int ans[])
{
int data[21], id[4] = {2, 3, 0, 1};// 要求數字串最小
for (int i = 0; i < 21; ++ i) {
data[i] = ans[i];
}
M2.clear();
int move = 1, save = 1;
qnode now(data, 0);
M2[now.state] = save;
Q2[save ++] = now;
while (move < save) {
now = Q2[move ++];
if (M1[now.state]) {
printf("%s",Q1[M1[now.state]].operate);
for (int i = now.steps-1; i >= 0; -- i) {
printf("%c",now.operate[i]);
}
puts("");
return 1;
}
if (now.steps > 8) {
return 0;
}
for (int i = 0; i < 4; ++ i) {
for (int j = 0; j < 21; ++ j) {
data[j] = now.state[j]-'0';
}
wheel_rotation(id[i], data);
qnode New(data, now.steps+1);
if (!M2[New.state]) {
M2[New.state] = save;
strcpy(New.operate, now.operate);
if (id[i] < 2) {
New.operate[now.steps] = id[i]+'3';
}else {
New.operate[now.steps] = id[i]-1+'0';
}
Q2[save ++] = New;
}
}
}
return 0;
}
int main()
{
int n, input[24];
scanf("%d",&n);
while (n --) {
for (int i = 0; i < 24; ++ i) {
scanf("%d",&input[i]);
}
if (match(input, ans)) {
puts("PUZZLE ALREADY SOLVED");
}else if (!bfs1(input, ans) && !bfs2(ans)) {
puts("NO SOLUTION WAS FOUND IN 16 STEPS");
}
}
return 0;
}