[Luogu2730] 魔板 Magic Squares

Description

在魔方风靡全球之后,RUBIK先生发明了它的简化版——魔板

如上表所示,魔板由8个同样大小的方块组成,每个方块的颜色均不相同,本题中分别用数字1-8表示,它们可能出现在魔板的任一位置。任一时刻魔板的状态都可以用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,得到数字序列即可表示此时魔板的状态。例如,序列(1、2、3、4、5、6、7、8)表示上表中魔板的状态,这也是本题中魔板的初始状态。对于魔板,可以施加三种不同操作,分别以A、B、C标识。具体操作如下:

A:上下行互换;

B:每一行同时循环右移一格;

C:中间4个方块顺时针旋转一格。

应用这三种基本操作,可以由任一状态达到任意另一状态。操作方法如下:

上表描述了上述3种操作的具体含义。表中方格外面的数字标识魔板的8个方块位置,方格内的数字表示此次操作前该方块所在位置。即:如果位置P中有数字I,则表示此次操作前方块所在位置I。

对于每种可能的状态,这三种基本操作都可以使用。

你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。

Input

只有一行,包括8个整数,用空格分开(这些整数在范围 1—8 之间)不换行,表示目标状态。

Output

Line 1: 包括一个整数,表示最短操作序列的长度

Line 2: 在字典序中最早出现的操作序列,用字符串表示

Sample Input

2 6 8 4 5 7 3 1 

Sample Output

7
BCABCCB

题解

这题很明显,是\(BFS\),对于可能出现重复状态,我们需要判重,我用的是\(Hash\)中常用的康托展开

以下是康托展开部分

int Calc(node q)
{
    int Res=0,c;
    for(int i=1;i<8;++i)
    {
        c=0;
        for(int j=i+1;j<=8;++j)
            if(q.mp[i]<q.mp[j]) ++c;
        Res+=c*fac[8-i];
    }
    return Res;
}

还可以写成

int Calc(node q)
{
    int Res=0,c;
    for(int i=8;i>1;--i)
    {
        c=0;
        for(int j=1;j<i;++j)
            if(q.mp[i]<q.mp[j]) ++c;
        Res+=c*fac[i-1];
    }
    return Res;
}

但需要注意的是无论怎样做,都需要让可能大一些的\(c\)乘以大阶乘,因为这样才能避免重复,一把辛酸泪



\(my~code\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
using namespace std;

const int Max_Size=1e+6;
struct node
{
    int mp[9],cnt,nx;
    char c;
}Q[Max_Size];
int l,r;
int goal[9];
int fac[]={1,1,2,6,24,120,720,5040,40320};
int Hash[40321];

int Calc(node q)
{
    int Res=0,c;
    for(int i=1;i<8;++i)
    {
        c=0;
        for(int j=i+1;j<=8;++j)
            if(q.mp[i]<q.mp[j]) ++c;
        Res+=c*fac[8-i];
    }
    /*
    for(int i=8;i>1;--i)
    {
        c=0;
        for(int j=1;j<i;++j)
            if(q.mp[i]<q.mp[j]) ++c;
        Res+=c*fac[i-1];
    }
    */
    return Res;
}

bool Check(node q)
{
    for(int i=1;i<=8;++i)
        if(q.mp[i]!=goal[i]) return 0;
    return 1;
}

void Output(int id)
{
    if(id==1) return;
    Output(Q[id].nx);
    printf("%c",Q[id].c);
}

void BFS()
{
    l=r=1;
    for(int i=1;i<=8;++i) Q[1].mp[i]=i;
    Q[1].cnt=0,Q[1].nx=-1,Hash[Calc(Q[1])]=1;
    node q; int tmp;
    while(l<=r)
    {
        if(Check(Q[l]))
        {
            printf("%d\n",Q[l].cnt),
            Output(l);
            return;
        }
        q=Q[l],++q.cnt,q.nx=l;
        //A
        for(int i=1;i<=8;++i) q.mp[i]=Q[l].mp[9-i];
        tmp=Calc(q);
        if(!Hash[tmp])
        {
            Hash[tmp]=1,q.c='A';
            ++r,Q[r]=q;
        }
        //B
        q.mp[1]=Q[l].mp[4];
        for(int i=2;i<=4;++i) q.mp[i]=Q[l].mp[i-1];
        q.mp[8]=Q[l].mp[5];
        for(int i=5;i<=7;++i) q.mp[i]=Q[l].mp[i+1];
        tmp=Calc(q);
        if(!Hash[tmp])
        {
            Hash[tmp]=1,q.c='B';
            ++r,Q[r]=q;
        }
        //C
        q.mp[1]=Q[l].mp[1],
        q.mp[4]=Q[l].mp[4],
        q.mp[5]=Q[l].mp[5],
        q.mp[8]=Q[l].mp[8],
        q.mp[2]=Q[l].mp[7],
        q.mp[3]=Q[l].mp[2],
        q.mp[6]=Q[l].mp[3],
        q.mp[7]=Q[l].mp[6],
        tmp=Calc(q);
        if(!Hash[tmp])
        {
            Hash[tmp]=1,q.c='C';
            ++r,Q[r]=q;
        }
        ++l;
    }
}

int main()
{
    for(int i=1;i<=8;++i) scanf("%d",&goal[i]);
    BFS();
    return 0;
}

原文地址:https://www.cnblogs.com/hihocoder/p/12129414.html

时间: 2024-09-29 23:59:07

[Luogu2730] 魔板 Magic Squares的相关文章

洛谷 P2730 魔板 Magic Squares

P2730 魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8个正整数来表示.可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列.对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示.这是基本状态. 这里提供三种基本操作,分别用大写字母“

洛谷P2730 魔板 Magic Squares

P2730 魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8个正整数来表示.可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列.对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示.这是基本状态. 这里提供三种基本操作,分别用大写字母“

魔板 Magic Squares

[题目描述]: 魔板 Magic Squares [思路]: 是不是感觉和八数码有点像? 显而易见的宽搜,把魔板的状态表示为排列,则状态最多有\(8! = 40320\)种,空间是可以接受的,对于是第几个排列可以用康拓展开来实现(我想在做八数码的时候你们都深知这个套路),然后根据题目中的三种方式转移状态,每个状态转移出\(3\)个子状态,注意判重!,一旦目标状态出现,那个所搜索的层数一定是能得到该状态的最小步数.最后就是代码细节多,要仔细. #include<cstdio> #include&

Luogu P2730 魔板 Magic Squares

P2730 魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8个正整数来表示.可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列.对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示.这是基本状态. 这里提供三种基本操作,分别用大写字母"

魔板 Magic Squares(广搜,状态转化)

题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8个正整数来表示.可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列.对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示.这是基本状态. 这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改

【题解】 LGP2730 【魔板 Magic Squares】

[题目背景] 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 [题目描述] 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8个正整数来表示.可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列.对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示.这是基本状态. 这里提供三种基本操作,分别用大写字母"A","B&quo

神器的方块Magic Squares

题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8个正整数来表示.可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列.对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示.这是基本状态. 这里提供三种基本操作,分别用大写字母"A","B",&

hdu1430魔板(广搜+康托展开+string应用)

魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2420    Accepted Submission(s): 511 Problem Description 在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板.魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示.任一时刻魔板的状态可用方块的颜色

BFS解Magic Squares

Magic Squares IOI'96 Following the success of the magic cube, Mr. Rubik invented its planarversion, called magic squares. This is a sheet composed of 8 equal-sizedsquares: 1 2 3 4 8 7 6 5 In this task we consider the version where each square has a d