BFS练习——三阶平面魔方

 

有一个  3×3 的平面魔方,在平面魔方中,每个格子里分别无重复地写上 1 - 9 这 9 个数字。一共有 4 种对平面魔方的操作:

  1. 选择某一行左移。

  2. 选择某一行右移。

  3. 选择某一列上移。

  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;
}

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值