• USACO 3.2 Magic Squares 【搜索+康托展开】


    题目背景

    在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有8个大小相同的格子的魔板:

    1 2 3 4 
    8 7 6 5

    题目描述

    我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示。这是基本状态。

    这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改变魔板的状态):

    “A”:交换上下两行;

    “B”:将最右边的一列插入最左边;

    “C”:魔板中央四格作顺时针旋转。

    下面是对基本状态进行操作的示范: 
    A: 
    1 2 3 4 ==> 8 7 6 5 
    8 7 6 5 ==> 1 2 3 4

    B: 
    1 2 3 4 ==> 4 1 2 3 
    8 7 6 5 ==> 5 7 6 5

    C: 
    1 2 3 4 ==> 1 7 2 4 
    8 7 6 5 ==> 8 6 3 5

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

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

    分析

    这题应当就是搜索了,但是到底是深搜还是广搜呢?注意到题目中说是要“用最少的基本操作”,也就是要求最短路径,那么就一定是广搜啦。但一定记住要在每次搜索的时候判重,那么我们如何记录这八个方块的状态呢?显然是可以用一个八维数组的,但是还可以有一种更为普遍的方法,那就是康托展开: 
    X=a[n](n-1)!+a[n-1](n-2)!+…+a[i]*(i-1)!+…+a[1]*0! 其中a[i]为当前未出现的元素中是排在第几个(从0开始)。 
    没错,它其实就是另一种特殊的字符串哈希,本质是把一个字符串中每个字符的位置和信息结合在一起,从而确立一个字符串的唯一性。有了这个方法,我们就可以AC了。

    下面是参考代码:

    /*
    ID: linda_f1
    PROG: msquare
    LANG: C++
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    int fac[9]={1,1,2,6,24,120,720,5040,40320};//contor 
    struct point
    {
        int a[10];
        int n;
        int step;
    }p[800000];
    int goal,bas,tot=0;
    int f[40320*3];
    bool vis[40320*3];
    
    int contor(int t)
    {
        int num=0,k=0;
        for(int i=1;i<=8;i++)
        {
            k=0;
            for(int j=i+1;j<=8;j++)
                if(p[t].a[i]>p[t].a[j]) 
                    k++;
            num+=k*fac[8-i];
        }
        return num;
    }
    
    
    void init()
    {
        for(int i=1;i<=4;i++)
            p[1].a[i]=i;
        for(int i=5;i<=8;i++)
            p[1].a[i]=13-i;
        vis[contor(1)]=1;
    }
    
    void out(int t)
    {
        if(t==1)
            return;
        out(f[t]);
        if(f[t]==1)
            cout<<tot<<endl;
        if(p[t].n==1)
            cout<<"A";
        if(p[t].n==2)
            cout<<"B";
        if(p[t].n==3)    
            cout<<"C";
    }
    
    void A(int t)
    {
        swap(p[t].a[1],p[t].a[5]);
        swap(p[t].a[2],p[t].a[6]);
        swap(p[t].a[3],p[t].a[7]);
        swap(p[t].a[4],p[t].a[8]);
    }
    
    void B(int t)
    {
        swap(p[t].a[4],p[t].a[3]);swap(p[t].a[8],p[t].a[7]);
        swap(p[t].a[3],p[t].a[2]);swap(p[t].a[7],p[t].a[6]);
        swap(p[t].a[2],p[t].a[1]);swap(p[t].a[6],p[t].a[5]);
    }
    
    void C(int t)
    {
        swap(p[t].a[2],p[t].a[3]);
        swap(p[t].a[2],p[t].a[7]);
        swap(p[t].a[2],p[t].a[6]);
    }
    
    
    void bfs()
    {
        int h=0,t=1;
        p[1].step=0;
        while(h<=t)
        {
            h++;
            for(int i=1;i<=3;i++)
            {
                t++;
                for(int j=1;j<=8;j++)
                    p[t].a[j]=p[h].a[j];
                if(i==1) A(t);
                if(i==2) B(t);
                if(i==3) C(t);
                bas=contor(t);
                if(vis[bas]) t--;
                else
                {
                    vis[bas]=1;
                    p[t].step=p[h].step+1;
                    p[t].n=i;
                    tot=p[t].step;
                    f[t]=h;
                    if(goal==bas)
                    {
                        out(t);
                        return ;                    
                    }
                }                            
            }
        }
    }
    
    int main()
    {
    //    freopen("msquare.in","r",stdin);
    //    freopen("msquare.out","w",stdout);
        init();//建立基本态
        for(int i=1;i<=4;i++)
            cin>>p[0].a[i];
        for(int i=5;i<=8;i++)
            cin>>p[0].a[13-i];
        goal=contor(0);
        if(vis[goal]) 
        {
            cout<<0<<endl;
            return 0;
        }
        bfs();
        cout<<endl;
        return 0;
    }
  • 相关阅读:
    C#发送邮件简单例子
    ABAP随笔
    日期格式转换
    正则校验金额,整数8位,小数3位。
    angular语法运用技巧
    Oracle中连接与加号(+)的使用
    含有代码分析的面试题
    面试的java题目
    递归查询
    本地没有ORACLE远程登录oracle服务器
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/7232589.html
Copyright © 2020-2023  润新知