有一个 3×3 的平面魔方,在平面魔方中,每个格子里分别无重复地写上 1 - 9 这 9 个数字。一共有 4 种对平面魔方的操作:
-
选择某一行左移。
-
选择某一行右移。
-
选择某一列上移。
-
选择某一列下移。
初始状态为
123 456 789
比如选择第一行左移,魔方会变成下面这样
231 456 789
现在给出魔方的一个状态,问你能否将魔方复原成初始状态。如果可以,计算最少操作次数。
输入格式
输入三行,每行三个 1 到 9 之间的整数。
输出格式
如果能还原成初始状态,输出最小的操作次数,否则输出 -1。
样例输入复制
412 756 389
样例输出复制
2
思路:
参考了一位大佬的思路,先将魔方的初始状态转为数字然后再用结构体存储,写一个函数来将数字转成字符数组然后进行相应的12种操作(转成数组是方便操作)(12种有:每一列的上移下移 每一行的左移右移)
然后就是用map来判重,因为此时9位数的可能性太多了,用vis数组判重就容易爆栈
通过此题,我还要去学习map的用法,以及sprintf 和 sscanf的用法
代码:
#include<iostream>
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int a, b, c, num;
map<int, int> m; //由于数字是9位数 有很多种数字情况,所以用map判重比vis数组好
struct node{
int k; //记录此时魔方代表的数字
int step; //记录此时的步骤数
node(int kk, int ss){
k = kk;
step = ss;
}
};
char s[100]; //后面会将数字转字符数组来模拟操作
//判断是否还原成功
bool checks(int nums){
return nums == 123456789;
}
//魔方的12种操作
int Operatoo(int i,int num) {
sprintf(s, "%d", num); //将数字转字符串
char temp = 0;
if(i == 1) { //第一行左移
temp = s[0];
s[0] = s[1],s[1] = s[2],s[2] = temp;
} else if(i == 2) { //第二行左移
temp = s[3];
s[3] = s[4],s[4] = s[5],s[5] = temp;
} else if(i == 3) { //第三行左移
temp = s[6];
s[6] = s[7],s[7] = s[8],s[8] = temp;
} else if(i == 4) {//第三列下移
temp = s[8];
s[8] = s[5],s[5] = s[2],s[2] = temp;
} else if(i == 5) {//第一行右移
temp = s[2];
s[2] = s[1],s[1] = s[0],s[0] = temp;
} else if(i == 6) {//第二行右移
temp = s[5];
s[5] = s[4],s[4] = s[3],s[3] = temp;
} else if(i == 7) {//第三行右移
temp = s[8];
s[8] = s[7],s[7] = s[6],s[6] = temp;
} else if(i == 8) {//第一列上移
temp = s[0];
s[0] = s[3],s[3] = s[6],s[6] = temp;
} else if(i == 9) {//第二列上移
temp = s[1];
s[1] = s[4],s[4] = s[7],s[7] = temp;
} else if(i == 10) {//第三列上移
temp = s[2];
s[2] = s[5],s[5] = s[8],s[8] = temp;
} else if(i == 11) {//第一列下移
temp = s[6];
s[6] = s[3],s[3] = s[0],s[0] = temp;
} else if(i == 12) {//第二列下移
temp = s[7];
s[7] = s[4],s[4] = s[1],s[1] = temp;
}
int numm;
sscanf(s, "%d", &numm); //将s数组转为numm数字
return numm;
}
int bfs(){
queue<node> q;
q.push(node(num, 0)); //初始数字入队
m[num] = 1; //对应map值标为1
while(!q.empty()){
node t = q.front();
q.pop();
if(checks(t.k)){ //检查是否还原
return t.step;
}
for(int i = 1; i <= 12; i++){ //枚举十二种操作
int temp = Operatoo(i, t.k);
if(m[temp] == 0){//map值为0说明该数字没有被找到过
q.push(node(temp, t.step + 1));
m[temp] = 1;
}
}
}
return -1; //不能还原
}
int main(){
scanf("%d%d%d", &a, &b, &c);
num = a * 1000000 + b * 1000 + c;//将魔方转成数字
cout << bfs() << endl;
return 0;
}