【算法实验三】--【分支限界法】--特殊的二阶魔方

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上面代码就可以完整的实现这个题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值