题目描述
在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有8个大小相同的格子的魔板:
1 2 3 4
8 7 6 5
我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示。这是基本状态。
这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改变魔板的状态):
“A”:交换上下两行;
“B”:将最右边的一列插入最左边;
“C”:魔板中央四格作顺时针旋转。
下面是对基本状态进行操作的示范:
A:
8 7 6 5
1 2 3 4
B:
4 1 2 3
5 8 7 6
C:
1 7 2 4
8 6 3 5
对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。
【输入格式】
输入有多组测试数据
只有一行,包括8个整数,用空格分开(这些整数在范围 1——8 之间),表示目标状态。
【输出格式】
Line 1: 包括一个整数,表示最短操作序列的长度。
Line 2: 在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。
Sample Input
2 6 8 4 5 7 3 1
Sample Output
7
BCABCCB
分析:
本题想要找到初始状态的魔板转换到目标状态最快的步骤,故利用BFS思想,由于需要知道每次变换的状态以及变换的步骤,故把状态以及步骤次序作为节点。设置一个队列,把初始状态放入队列中,不断取出,并判断当前状态的可行变换,并保存至队列中,直到找到目标状态。
要点:
由于需要知道到达目标状态的路径,因此需要把之前的变换步骤一起保存至节点中;
为了减少队列的级数,因此采取在变换时就判断节点是否到达终点,而不是先放入队列等取出在判断,节省空间;
由于是在变换时判断节点是否为终点,若是初始状态即为终点,就会出现无法在一开始判断的情况,因此需要在一开始对初始状态进行判断;
为了减少重复访问状态,利用Hash表记录状态,在变换时判断,若是重复则判断为不可行的变换。
#include <iostream>
#include <queue>
#include <string>
#include <map>
using namespace std;
int en[2][4];
int n[2][4] = {1, 2, 3, 4, 8, 7, 6, 5};
int jui[2][2] = {0, 1, -1, 0};
int juj[2][2] = {1, 0, 0, -1};
char op[3] = {'A', 'B', 'C'};
struct mboard{
int ju[2][4];
string s;
int step;
}be, temp;
int Hash(int a[2][4]){
int index = 0;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
index *= 10;
index += a[i][j];
}
}
return index;
}
void Print(int a[2][4]){
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
cout << a[i][j] << ' ';
}
cout << '\n';
}
}
void A(int a[2][4]){
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
temp.ju[(i + 1) % 2][j] = a[i][j];
}
}
}
void B(int a[2][4]){
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
temp.ju[i][(j + 1) % 4] = a[i][j];
}
}
}
void C(int a[2][4]){
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
if(j == 0 || j == 3) temp.ju[i][j] = a[i][j];
else{
temp.ju[i + jui[i][j - 1]][j + juj[i][j - 1]] = a[i][j];
}
}
}
}
bool Match(void){
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
if(temp.ju[i][j] != en[i][j]) return false;
}
}
return true;
}
void BFS(void){
temp = be;
if(Match()){
cout << temp.step << '\n';
cout << '\n';
return;
}
map<int, bool> mp;
mp[Hash(temp.ju)] = true;
queue<mboard> q;
q.push(be);
while(!q.empty()){
mboard now;
now = q.front();
q.pop();
for(int k = 0; k < 3; k++){
temp = now;
switch(k){
case 0:A(now.ju);
break;
case 1:B(now.ju);
break;
case 2:C(now.ju);
break;
}
temp.s += op[k];
temp.step += 1;
if(Match()){
cout << temp.step << '\n';
for(int i = 0; i < temp.s.size(); i++){
cout << temp.s[i];
}
cout << '\n';
return;
}
if(mp[Hash(temp.ju)] == true) continue;
else mp[Hash(temp.ju)] = true;
q.push(temp);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
for(int i = 0; i < 2; i++){
for(int j = 0; j < 4; j++){
be.ju[i][j] = n[i][j];
}
}
be.step = 0;
while(cin >> en[0][0]){
for(int j = 1; j < 4; j++){
cin >> en[0][j];
}
for(int j = 0; j < 4; j++){
cin >> en[1][3 - j];
}
BFS();
}
return 0;
}