洛谷 P2730 魔板 Magic Squares

题意

一块初始的2*4的模板,有三种变动方式,给定目标状态,求出最少要多少步变成目标状态,并输出变动方式。

做法

第一眼看这题的时候,心里就想:这不就是BFS吗,居然有提高+的水准(最多普及-),但这个内存是真心恶心,如果开八维存下每种数量的话肯定MLE,所以我们可以用一个24位的二进制存下一种方案,再加上BFS即可。

代码

复制代码
#include<bits/stdc++.h>
using namespace std;
int d[1<<24];//最多24位,记录成为这个状态的最小步数 
int q[50000];//BFS的队列 
int qian[50000];//记录上一步的状态 
char c[50000];//记录上一步的行动(A,B,C之一) 
void jiami(int k,int s[])
{
    for(int i=7;i>=0;--i)
       s[i]=k&7,k>>=3;
}//转化成八个整数 
int jiexi(int ins[])
{
    int ans=0;
    for(int i=0;i<8;++i)
        ans<<=3,ans|=ins[i];
    return ans;    
}//转化成二进制 
int main() 
{

    //freopen("msquare.in","r",stdin);
    //freopen("msquare.out","w",stdout);
    int x,y;
    x=y=0;
    int a; 
    for(int i=0;i<8;++i)
       scanf("%d",&a),--a,x<<=3,x|=a,y<<=3,y|=i;//二进制保存 
    if(x==y) 
    {
        printf("0\n\n");
        return 0;
    }//特判一下 
    memset(d,-1,sizeof(d));//初始值为-1表示还没有变成这个状态 
    d[y]=0;//一开始的次数是0 
    int head,tail;
    q[head=tail=1]=y;//一开始的状态 
    while(head<=tail)
    {
        int p=q[head];
        int s[8],t[8];
        jiami(p,s);//转化成八个整数存入s数组 
        for(int i=0;i<8;++i)
            t[i]=s[i];
        for(int i=0;i<4;++i)
           swap(t[i],t[7-i]);//交换上下两行    
        int ok=jiexi(t);//再转化成整数  
        if(d[ok]==-1)
        {
            q[++tail]=ok;
            d[ok]=d[p]+1;
            c[tail]='A'; 
            qian[tail]=head;
            if (ok == x) break; 
        }//下面的都差不多 
        for(int i=0;i<8;++i)
            t[i]=s[i];
        for(int i=3;i>=1;--i)
            swap(t[i],t[i-1]);//把第一行的最右边的插入最左边的 
        for(int i=4;i<=6;++i)
            swap(t[i],t[i+1]); //把第二行的最右边的插入最左边的 
        ok=jiexi(t);  
        if(d[ok]==-1)
        {
            q[++tail]=ok;
            d[ok]=d[p]+1;
            c[tail]='B';
            qian[tail]=head;
            if (ok == x) break;
        }    
        for(int i=0;i<8;++i)
            t[i]=s[i];
        int tea=t[1];
        t[1]=t[6];
        t[6]=t[5];
        t[5]=t[2];
        t[2]=tea;//直接暴力枚举   
        ok=jiexi(t);  
        if(d[ok]==-1)
        {
            q[++tail]=ok;
            d[ok]=d[p]+1;
            c[tail]='C';
            qian[tail]=head;
            if (ok == x) break;
        }    
        ++head;
    }
    printf("%d\n", d[x]);
    string sf;//记录最终答案 
    int now = tail;
    while (q[now] != y)
    {
        sf += c[now];
        now = qian[now];
    }//倒推 
    int l = sf.size();
    int us=0;
    for (int i = l-1; i >=0; --i)
    {
        printf("%c", sf[i]);
        ++us;
        if (i == 0 ||  us% 60 == 0)
           puts("");//换行(不加也可以,次数不会超60) 
    }
    return 0; 
}
复制代码

 

posted @   LikC1606  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示