1325.特殊的二阶魔方
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
魔方大家应该都玩过。现在有一个特殊的二阶魔方,它只有一面是白色,其余五个面全是黑色。玩这个魔方当然也有特殊的规则,玩家只能通过六种方式去改变它,底层向左转一格(称为DL),底层向右转一格(称为DR),右侧向上转一格(称为RU),右侧向下转一格(称为RD),内侧顺时针转一格(称为C),内侧逆时针转一格(称为CC)。现给一魔方的状态,请在最少的步骤内把魔方还原
输入
按照上下左右前后的顺序给出各面的具体情况,0表示白色,1表示黑色。上下、左右、前后分别是以俯视图、左视图、正视图看到的
输出
输出令一面全为白色的最小步数。
#include <iostream>
#include <queue>
using namespace std;
struct node
{
int cube[6][4]; //六个面,每面四块
//面的顺序为上下左右前后
int num[6]; //六个面,每个面进行二进制编码,再转换成十进制存在num数组中
};
queue <node> q1;
int step[16][16][16][16][16][16]; //存储到达这一状态的步数
int used[16][16][16][16][16][16]; //判重数组
int bfs(); //深搜
node setnum(node n1); //计算num数组的值
bool canmoveto(node n1, node n2); //对n2节点进行判重
//若重复,直接返回false
//若不重复,则标记used数组,更新step数组
node moveto(node n1, int d); //返回n1状态经由d操作之后获得的新状态
bool eqtarget(node n1); //判断是否到达目标状态
int main()
{
node start;
for(int i=0; i<6; i++)
{
for(int j=0; j<4; j++)
{
start.cube[i][j]=cin.get()-'0'; //将字符转成数字
if(j==1)cin.get(); //吃掉回车符
}
cin.get(); //吃掉回车符
}
start=setnum(start); //计算start节点的num数组
/*
for(int i=0; i<4; i++)
cout<<start.cube[1][i]<<' ';
cout<<endl;
for(int i=0; i<6; i++)
cout<<start.num[i]<<' ';
cout<<endl;
*/
if(eqtarget(start)) //一开始就到达目标状态
{
cout<<'0'<<endl;
}
else
{
q1.push(start); //入队
//初始步数为0
step[start.num[0]][start.num[1]][start.num[2]][start.num[3]][start.num[4]][start.num[5]]=0;
//标记初始状态用过
used[start.num[0]][start.num[1]][start.num[2]][start.num[3]][start.num[4]][start.num[5]]=1;
//开始广搜
cout<<bfs()<<endl;
}
return 0;
}
int bfs()
{
node top,next;
while(!q1.empty())
{
top=q1.front();
q1.pop();
for(int i=0; i<6; i++) //六种操作
{
next=moveto(top, i); //经过i操作,获得新的next状态
if(canmoveto(top, next)) //对next状态进行判重,不重复就更新used数组和step数组
{
if(eqtarget(next)) //达到目标状态就返回步数
{
return step[next.num[0]][next.num[1]][next.num[2]][next.num[3]][next.num[4]][next.num[5]];
}
else //没达到目标状态就入队,等待下次pop扩展
{
q1.push(next);
}
}
}
}
return -1; //如果没搜到,返回-1
}
//计算n1节点的num数组
node setnum(node n1)
{
for(int i=0; i<6; i++) //六个面
{
n1.num[i]=0; //清空num
for(int j=0; j<4; j++) //每面4块,0==白,1==