• H 幻方变换(puzzle)(NYIST 2019年校赛)


    • H 幻方变换(puzzle)(NYIST 2019年校赛)

    如果一个 3 × 3 的矩阵中,整数 1-9 中的每个都恰好出现一次,我们称这个矩阵为一个幻 方。

    我们可以对一个幻方进行一些操作。具体来说,我们可以

    • 选择幻方的一行,整体向右移动一格,并将最右侧的数字移到最左边;或者

    • 选择幻方的一列,整体向下移动一格,并将最下侧的数字移到最上面。

    例如,下面两个操作分别是一种合法的行操作和列操作:

    img

    显然,一个合法的幻方经过一次操作后一定还是合法的幻方。

    给定幻方的初始状态,请问,最少要经过多少次变换,才能变成最终状态?

    输入描述:

    第一行一个整数 T (1 ≤ T ≤ 200000),表示测试用例的数量。
    
    接下来有 T 组测试用例,每组测试用例前有一个空行。每组样例的前 3 行为幻方的初始状态,后 3 行为幻方的最终状态。每行的数字之间没有空格。
    
    保证初始状态和最终状态都是合法的幻方。
    

    输出描述:

    对于每组测试用例在一行内输出一个整数,表示答案。如果不可能从起始状态转变为最终状态,输出 impossible。
    

    样例输入:

    4
    
    123
    456
    789
    231
    456
    789
    
    457
    213
    689
    257
    361
    489
    
    927
    641
    358
    297
    651
    384
    
    123
    456
    789
    123
    456
    789
    

    样例输出:

    2
    3
    impossible
    0
    

    分析:

    ​ $广搜即可。不过因为是t组输入,即每一次广搜的最坏次数为9!,故每一次都广搜的话会超时 $

    ​ 我们可以预处理出123 456 789 到所有状态的的最小次数,然后对于题目要求输入的初始状态和最终状态,只需把初始状态对应位置的数字都对应为123 456 789,并且把最终状态的按照这种规则转化一下。那么只需求123 456 789这种状态到转换后的最终状态的最短距离即可。因为预处理了,可以O(1)时间内求出来。

    故可分为下列步骤

    1. 预处理123 456 789到其他所有状态的最少操作次数(广搜即可)

      ​ 需要注意以下问题

      • 对于幻方的状态可以用每一行拼接后的字符串表示
      • 定义幻方旋转第ii行和旋转第ii列的操作
    2. 将输入的最初状态转换为123 456 789转换并记录下规则

    3. 将输入的最终状态按照 第二步 的规则转化为可以求的最终状态

    4. O(1)出答案即可

    代码:

    #include<bits/stdc++.h>
    #define mset(a,b)   memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    struct HuanF{
        string s;
        int step;
        HuanF Row_right(int k)//第k行向右旋转
        {
            HuanF ans;
            ans.s=s;
            char c=ans.s[3*k+2];
            ans.s[3*k+2]=ans.s[3*k+1];
            ans.s[3*k+1]=ans.s[3*k];
            ans.s[3*k]=c;
            return ans;
        }
        HuanF  Colu_down(int k)
        {
            HuanF ans;
            ans.s=s;
            char c=ans.s[k+6];
            ans.s[k+6]=ans.s[k+3];
            ans.s[k+3]=ans.s[k];
            ans.s[k]=c;
            return  ans;
        }
        void Print()
        {
            for(int i=0;i<s.length();++i)
            {
                printf("%c%c",s[i],i%3==2?'
    ':' ');
            }
            printf("step=%d
    ",step);
        }
    };
    bool operator <(const HuanF &a ,const HuanF& b)
    {
            return a.s<b.s;
    }
    map<HuanF,int> book;//记录有没有出现过
    map<HuanF,int> dis;//记录最小值
    void init()
    {
        int times=0;
        HuanF now;
        now.s="123456789";
        now.step=0;
        queue<HuanF> mmp;
        mmp.push(now);
        book[now]=1;
        dis[now]=0;
        while(!mmp.empty())
        {
            HuanF mm=mmp.front();
            mmp.pop();
            for(int i=0;i<3;++i)
            {
                HuanF Net=mm.Colu_down(i);
                if(!book[Net])
                {
                    dis[Net]=mm.step+1;
                    Net.step=mm.step+1;
                    book[Net]=1;
                    mmp.push(Net);
                }
                Net=mm.Row_right(i);
                if(!book[Net])
                {
                    dis[Net]=mm.step+1;
                    book[Net]=1;
                    Net.step=mm.step+1;
                    mmp.push(Net);
                }
            }
        }
    }
    int Hash[10];//将魔方中的数字 分别对应 1 2 3 4 5
    int main()
    {
        int t;
        init();
        scanf("%d",&t);
        char ss[10];
        char zz[10];
        while(t--)
        {
            for(int i=0;i<3;++i)
            {
                scanf("%s",ss+(i*3));
            }
            for(int i=0;i<9;++i)
            {
                Hash[ss[i]-'0']=i+1;
            }
            for(int i=0;i<3;++i)
            {
                scanf("%s",zz+(i*3));
            }
            for(int i=0;i<9;++i)
            {
                zz[i]=Hash[zz[i]-'0']+'0';
            }
            zz[9]='';
            HuanF ret;
            ret.s=string(zz);
            if(ret.s!="123456789"&&dis[ret]==0)
            {
                cout<<"impossible"<<endl;
            }
            else
                cout<<dis[ret]<<endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    KMP算法
    字典树从第i个构造HDU2846
    字典树的数组实现 HDU1671
    kruskal算法的套路
    HDU1598最小生成树+贪心处理
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    springBoot启动报 `NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;`问题解决
    redis远程连接 安全模式问题解决
  • 原文地址:https://www.cnblogs.com/dchnzlh/p/10546538.html
Copyright © 2020-2023  润新知