1325.特殊的二阶魔方
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
魔方大家应该都玩过。现在有一个特殊的二阶魔方,它只有一面是白色,其余五个面全是黑色。玩这个魔方当然也有特殊的规则,玩家只能通过六种方式去改变它,底层向左转一格(称为DL),底层向右转一格(称为DR),右侧向上转一格(称为RU),右侧向下转一格(称为RD),内侧顺时针转一格(称为C),内侧逆时针转一格(称为CC)。现给一魔方的状态,请在最少的步骤内把魔方还原
输入
按照上下左右前后的顺序给出各面的具体情况,0表示白色,1表示黑色。上下、左右、前后分别是以俯视图、左视图、正视图看到的
输出
输出令一面全为白色的最小步数。
输入样例
00
00
11
11
11
11
11
11
11
11
11
11
输出样例
0
题解:这个也是一个很明显的广搜和队列解决的问题。我们的大概思路是在bfs里边,for循环里边有六种可以转动魔方的方法,每个入队列并进行比较即可。那么这里存在两个问题。第一个我们应该如何记录魔方的状态,其六个面每个面四个块,我们不可能用一个24位的整数记录;随之而来的第二个问题我们如何进行状态查重。
那么我们对问题进行解决。对于这六个面24个块,既然不能用map函数解决,那么我们用我们的原始方法,设一个二位数组存这六个面24个块所表示的状态,即cube[6][4],分别存上下,左右,前后的状态,即cube[0]存的是上面四个,cube[3]存的是右面四个,诸如此类。然后对应的,在进行旋转时要注意换哪几个块。然后记录对应的uesd和step,这里我们可以创建一个结构体node,里边包含二维数组cube,也包含对应状态和步数即used和step的int变量,根据节点来递增改变step的值。
那么对于队列,我们设一个node型的队列,把每个节点存进去即可。
说一下旋转变换。底层向右转一格:变换的是下前后左右五面,只有上面没变,所以对应的要改变cube[1~5],至于怎么变大家自行思考,详见代码:
#include <iostream>
#include<queue>
#include<string.h>
#include<stdio.h>
using namespace std;
struct node{
int cube[6][4];
int used=0;
int step=0;
};
queue<node> q;
int num=0;
node m[100];
void init_readdata()
{
memset(m,0,sizeof(m));
while(!q.empty())
q.pop();
num=0;
for(int j=0;j<6;j++)
{
for(int k=0;k<4;k++)
{
scanf("%d",&m[0].cube[j][k]);
}
}
m[0].used=1;
m[0].step=1;
num++;
q.push(m[0]);
}
int compare(node cur)
{
for(int i=0;i<6;i++)
{
if(cur.cube[i][0]==0&&cur.cube[i][1]==0&&cur.cube[i][2]==0&&cur.cube[i][3]==0)
return 1;
}
return 0;
}
node moveto(node n1,int i)
{
node n2=n1;
switch(i)//上下 左右 前后,分别以俯视图,左视图,正视图来记录顺序
{
case 0://DL,底层向左旋转一格
{
n2.cube[4][2]=n1.cube[3][3];//变前边
n2.cube[4][3]=n1.cube[3][2];
n2.cube[3][2]=n1.cube[5][2];//右边
n2.cube[3][3]=n1.cube[5][3];
n2.cube[5][2]=n1.cube[2][3];//变后边
n2.cube[5][3]=n1.cube[2][2];
n2.cube[2][2]=n1.cube[4][2];//变左边
n2.cube[2][3]=n1.cube[4][3];
n2.cube[1][0]=n1.cube[1][2];//下边
n2.cube[1][1]=n1.cube[1][0];
n2.cube[1][2]=n1.cube[1][3];
n2.cube[1][3]=n1.cube[1][1];
break;
}
case 1://底层向右转一格(称为DR)
{
n2.cube[4][2]=n1.cube[2][2];//变前边
n2.cube[4][3]=n1.cube[2][3];
n2.cube[3][2]=n1.cube[4][3];//右边
n2.cube[3][3]=n1.cube[4][2];
n2.cube[5][2]=n1.cube[3][2];//变后边
n2.cube[5][3]=n1.cube[3][3];
n2.cube[2][2]=n1.cube[5][3];//变左边
n2.cube[2][3]=n1.cube[5][2];
n2.cube[1][0]=n1.cube[1][1];//下边
n2.cube[1][1]=n1.cube[1][3];
n2.cube[1][2]=n1.cube[1][0];
n2.cube[1][3]=n1.cube[1][2];
break;
}
case 2://右侧向上转一格(称为RU)
n2.cube[0][1]=n1.cube[4][1]; //
n2.cube[0][3]=n1.cube[4][3];
n2.cube[4][1]=n1.cube[1][3]; //
n2.cube[4][3]=n1.cube[1][1];
n2.cube[1][1]=n1.cube[5][1]; //
n2.cube[1][3]=n1.cube[5][3];
n2.cube[5][1]=n1.cube[0][3]; //
n2.cube[5][3]=n1.cube[0][1];
n2.cube[3][0]=n1.cube[3][1]; //
n2.cube[3][1]=n1.cube[3][3];
n2.cube[3][3]=n1.cube[3][2];
n2.cube[3][2]=n1.cube[3][0];
break;
case 3: //右侧向下转一格(RD)
{
n2.cube[0][1]=n1.cube[5][3]; //上面
n2.cube[0][3]=n1.cube[5][1];
n2.cube[5][1]=n1.cube[1][1]; //后面
n2.cube[5][3]=n1.cube[1][3];
n2.cube[1][1]=n1.cube[4][3]; //下面
n2.cube[1][3]=n1.cube[4][1];
n2.cube[4][1]=n1.cube[0][1]; //前面
n2.cube[4][3]=n1.cube[0][3];
n2.cube[3][0]=n1.cube[3][2]; //右面
n2.cube[3][2]=n1.cube[3][3];
n2.cube[3][3]=n1.cube[3][1];
n2.cube[3][1]=n1.cube[3][0];
break;
}
case 4: //内侧顺时针转一格(C)
{
n2.cube[0][2]=n1.cube[2][3]; //上面
n2.cube[0][3]=n1.cube[2][1];
n2.cube[2][1]=n1.cube[1][2]; //左面
n2.cube[2][3]=n1.cube[1][3];
n2.cube[1][2]=n1.cube[3][3]; //下面
n2.cube[1][3]=n1.cube[3][1];
n2.cube[3][1]=n1.cube[0][2]; //右面
n2.cube[3][3]=n1.cube[0][3];
n2.cube[4][0]=n1.cube[4][2]; //内侧
n2.cube[4][2]=n1.cube[4][3];
n2.cube[4][3]=n1.cube[4][1];
n2.cube[4][1]=n1.cube[4][0];
break;
}
case 5: //内侧逆时针转一格(CC)
{
n2.cube[0][2]=n1.cube[3][1]; //上面
n2.cube[0][3]=n1.cube[3][3];
n2.cube[3][1]=n1.cube[1][3]; //右面
n2.cube[3][3]=n1.cube[1][2];
n2.cube[1][2]=n1.cube[2][1]; //下面
n2.cube[1][3]=n1.cube[2][3];
n2.cube[2][1]=n1.cube[0][3]; //左面
n2.cube[2][3]=n1.cube[0][2];
n2.cube[4][0]=n1.cube[4][1]; //内侧
n2.cube[4][1]=n1.cube[4][3];
n2.cube[4][3]=n1.cube[4][2];
n2.cube[4][2]=n1.cube[4][0];
break;
}
}
return n2;
}
int check(node n)
{
int flag=0;
for(int i=0;i<num;i++)
{
flag=0;
for(int j=0;j<6;j++)
{
for(int k=0;k<4;k++)
{
if(m[i].cube[j][k]!=n.cube[j][k])
flag=1;
}
}
if(flag==0)
return 0;
}
return 1;
}
int bfs()
{
while(!q.empty())
{
node cur;
cur=q.front();
q.pop();
if(compare(cur))
return cur.step;
else
{
for(int i=0;i<6;i++)
{
node res=moveto(cur,i);
if(check(res))
{
q.push(res);
m[num]=res;
m[num].used=1;
m[num].step=cur.step+1;
num++;
}
}
}
}
return 0;
}
int main()
{
init_readdata();
cout<<bfs()<<endl;
return 0;
}
以上是第一版代码,这里我用的查重是将所有走过的记录下来,对于每个新状态遍历,所以结构体中的used变量显然没有什么用处,但是代码整体来说应该没有什么问题的。但是代码运行结果不对,不知道为什么,希望有大神看出来的话可以留言指导。
后来我又想到可以用used数组,像六数码那样,既然24个格子得出的数太大,那么我可以来个六维数组,每一维分别对应上下左右前后六个位置的四个格子换算出来的数,这样我就不用遍历了,同时也有配套的step可以使用。代码如下:
#include <iostream>
#include<queue>
#include<string.h>
#include<stdio.h>
using namespace std;
struct node{
int cube[6][4];
int tube[6];
};
int used[16][16][16][16][16][16];
int step[16][16][16][16][16][16];
queue<node> q;
int num=0;
node m;
void init_readdata()
{
//memset(m,0,sizeof(m));
memset(used,0,sizeof(used));
memset(step,0,sizeof(step));
while(!q.empty())
q.pop();
for(int j=0;j<6;j++)
for(int k=0;k<4;k++)
scanf("%d",&m.cube[j][k]);
for(int j=0;j<6;j++)
m.tube[j]=m.cube[j][0]*8+m.cube[j][1]*4+m.cube[j][2]*2+m.cube[j][3];
q.push(m);
used[m.tube[0]][m.tube[1]][m.tube[2]][m.tube[3]][m.tube[4]][m.tube[5]]=1;
step[m.tube[0]][m.tube[1]][m.tube[2]][m.tube[3]][m.tube[4]][m.tube[5]]=0;
}
int compare(node cur)
{
for(int i=0;i<6;i++)
{
if(cur.cube[i][0]==0&&cur.cube[i][1]==0&&cur.cube[i][2]==0&&cur.cube[i][3]==0)
return 1;
}
return 0;
}
node moveto(node n1,int i)
{
node n2=n1;
switch(i)//上下 左右 前后,分别以俯视图,左视图,正视图来记录顺序
{
case 0://DL,底层向左旋转一格
{
n2.cube[4][2]=n1.cube[3][3];//变前边
n2.cube[4][3]=n1.cube[3][2];
n2.cube[3][2]=n1.cube[5][2];//右边
n2.cube[3][3]=n1.cube[5][3];
n2.cube[5][2]=n1.cube[2][3];//变后边
n2.cube[5][3]=n1.cube[2][2];
n2.cube[2][2]=n1.cube[4][2];//变左边
n2.cube[2][3]=n1.cube[4][3];
n2.cube[1][0]=n1.cube[1][2];//下边
n2.cube[1][1]=n1.cube[1][0];
n2.cube[1][2]=n1.cube[1][3];
n2.cube[1][3]=n1.cube[1][1];
break;
}
case 1://底层向右转一格(称为DR)
{
n2.cube[4][2]=n1.cube[2][2];//变前边
n2.cube[4][3]=n1.cube[2][3];
n2.cube[3][2]=n1.cube[4][3];//右边
n2.cube[3][3]=n1.cube[4][2];
n2.cube[5][2]=n1.cube[3][2];//变后边
n2.cube[5][3]=n1.cube[3][3];
n2.cube[2][2]=n1.cube[5][3];//变左边
n2.cube[2][3]=n1.cube[5][2];
n2.cube[1][0]=n1.cube[1][1];//下边
n2.cube[1][1]=n1.cube[1][3];
n2.cube[1][2]=n1.cube[1][0];
n2.cube[1][3]=n1.cube[1][2];
break;
}
case 2://右侧向上转一格(称为RU)
n2.cube[0][1]=n1.cube[4][1]; //
n2.cube[0][3]=n1.cube[4][3];
n2.cube[4][1]=n1.cube[1][3]; //
n2.cube[4][3]=n1.cube[1][1];
n2.cube[1][1]=n1.cube[5][1]; //
n2.cube[1][3]=n1.cube[5][3];
n2.cube[5][1]=n1.cube[0][3]; //
n2.cube[5][3]=n1.cube[0][1];
n2.cube[3][0]=n1.cube[3][1]; //
n2.cube[3][1]=n1.cube[3][3];
n2.cube[3][3]=n1.cube[3][2];
n2.cube[3][2]=n1.cube[3][0];
break;
case 3: //右侧向下转一格(RD)
{
n2.cube[0][1]=n1.cube[5][3]; //上面
n2.cube[0][3]=n1.cube[5][1];
n2.cube[5][1]=n1.cube[1][1]; //后面
n2.cube[5][3]=n1.cube[1][3];
n2.cube[1][1]=n1.cube[4][3]; //下面
n2.cube[1][3]=n1.cube[4][1];
n2.cube[4][1]=n1.cube[0][1]; //前面
n2.cube[4][3]=n1.cube[0][3];
n2.cube[3][0]=n1.cube[3][2]; //右面
n2.cube[3][2]=n1.cube[3][3];
n2.cube[3][3]=n1.cube[3][1];
n2.cube[3][1]=n1.cube[3][0];
break;
}
case 4: //内侧顺时针转一格(C)
{
n2.cube[0][2]=n1.cube[2][3]; //上面
n2.cube[0][3]=n1.cube[2][1];
n2.cube[2][1]=n1.cube[1][2]; //左面
n2.cube[2][3]=n1.cube[1][3];
n2.cube[1][2]=n1.cube[3][3]; //下面
n2.cube[1][3]=n1.cube[3][1];
n2.cube[3][1]=n1.cube[0][2]; //右面
n2.cube[3][3]=n1.cube[0][3];
n2.cube[4][0]=n1.cube[4][2]; //内侧
n2.cube[4][2]=n1.cube[4][3];
n2.cube[4][3]=n1.cube[4][1];
n2.cube[4][1]=n1.cube[4][0];
break;
}
case 5: //内侧逆时针转一格(CC)
{
n2.cube[0][2]=n1.cube[3][1]; //上面
n2.cube[0][3]=n1.cube[3][3];
n2.cube[3][1]=n1.cube[1][3]; //右面
n2.cube[3][3]=n1.cube[1][2];
n2.cube[1][2]=n1.cube[2][1]; //下面
n2.cube[1][3]=n1.cube[2][3];
n2.cube[2][1]=n1.cube[0][3]; //左面
n2.cube[2][3]=n1.cube[0][2];
n2.cube[4][0]=n1.cube[4][1]; //内侧
n2.cube[4][1]=n1.cube[4][3];
n2.cube[4][3]=n1.cube[4][2];
n2.cube[4][2]=n1.cube[4][0];
break;
}
}
for(int j=0;j<6;j++)
n2.tube[j]=n2.cube[j][0]*8+n2.cube[j][1]*4+n2.cube[j][2]*2+n2.cube[j][3];
return n2;
}
int bfs()
{
while(!q.empty())
{
node cur;
cur=q.front();
q.pop();
for(int i=0;i<6;i++)
if(cur.tube[i]==0)
return step[cur.tube[0]][cur.tube[1]][cur.tube[2]][cur.tube[3]][cur.tube[4]][cur.tube[5]];
else
{
for(int i=0;i<6;i++)
{
node res=moveto(cur,i);
if(!used[res.tube[0]][res.tube[1]][res.tube[2]][res.tube[3]][res.tube[4]][res.tube[5]])
{
q.push(res);
used[res.tube[0]][res.tube[1]][res.tube[2]][res.tube[3]][res.tube[4]][res.tube[5]]=1;
step[res.tube[0]][res.tube[1]][res.tube[2]][res.tube[3]][res.tube[4]][res.tube[5]]=
step[cur.tube[0]][cur.tube[1]][cur.tube[2]][cur.tube[3]][cur.tube[4]][cur.tube[5]]+1;
}
}
}
}
return 0;
}
int main()
{
init_readdata();
cout<<bfs()<<endl;
return 0;
}
s上面代码就可以完整的实现这个题了。