zoukankan      html  css  js  c++  java
  • HDU 1430 魔板

    在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板。魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示。任一时刻魔板的状态可用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,所得到的数字序列即可表示此时魔板的状态。例如,序列(1,2,3,4,5,6,7,8)表示魔板状态为:


    1 2 3 4
    8 7 6 5

    对于魔板,可施加三种不同的操作,具体操作方法如下:

    A: 上下两行互换,如上图可变换为状态87654321
    B: 每行同时循环右移一格,如上图可变换为41236785
    C: 中间4个方块顺时针旋转一格,如上图可变换为17245368

    给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。

    hdu 链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430

    BFS + 康拓展开 + 打表 + 映射 

    #include <bits/stdc++.h> 
    const int N = 8; 
    const int MAX = 40323;
    using namespace std;
    
    /*
    魔板 hdu 1430 搜索 + 康拓展开。
     http://acm.hdu.edu.cn/showproblem.php?pid=1430
     
    BFS + 打表预处理 + 康拓展开 
    https://www.cnblogs.com/H-Vking/p/4346004.html
    
    关于打表预处理:
    
      由于魔板的所有状态都可以转换为“12345678”,
    所以这时就需要做一个映射:每组数据都有一个起始状态与目标状态,
    可以把起始状态用一种映射关系映射为“12345678”,
    然后用这种映射关系再去改一下终止状态。例如:初态为“12653487” , 
    目态为“12345678” ;这时映射后初态为“12345678”,
    即f[1] = 1 , f[2] = 2 , f[6] = 3 , f[5] = 4 , f[3] = 5 , 
    f[4] = 6 , f[8] = 7 , f[7] = 8 ,按照这种
    映射关系目态应为“12564387”。
    代码应为:f[start[i] - '0'] = i ; end[i] = f[end[i] - '0'] + '0';
    
     有这样一个映射前提,
    可以先用BFS预处理从“12345678”到其余所有状态的步骤,
    然后输入每组测试数据后进行转换,然后这时候就变成了
    求从“12345678”到映射后的目标状态的步骤的问题,
    这时按照存好的路径输出即可。
    */
    
    struct no
    {
      int num;//上一状态的编号 
      int c;
      no(){
          num = -1;c =-1;
      }
    }dis[MAX]; 
    
    typedef struct 
    {
        int num;//对应kt编号 
        string st;
    }node;
    
    int fac[] = {1,1,2,6,24,120,720,5040,40320};
    string str;//初始状态 
    string Tstr;//目标状态 
    int Tflag ;
    int q;
    
    queue<node> qu;
    
    //康拓的逆(这题不需要)
    void ktn(char a[9],int k)
    {  
        k--;//这别忘了,第12个,一定从11开始计算 
       int vis[10]={0};int j = 0;
       for (int i=0;i<N;++i)
        {
            int t = k/fac[N-i-1];
            for ( j=1;j<=N;++j) //计算出它到底是几,这里要排除出现过的数 
              if (!vis[j])
                {
                  if (!t) break;
                  t--;
                }
            a[i]=j+'0';
            vis[j] =1; 
            k %= fac[N-i-1]; 
        }
        
    } 
    
    //康拓展开
     
    int kt(string &arr)
    {
        int ans =  0 ;
       for (int i=0;i<N;++i)
        {
            int t = 0; //记录后面比它小的数字个数 
          for (int j = i+1;j<N;++j)
           {
                if (arr[j] < arr[i]) t++;
           }
          ans += t*fac[N-i-1]; 
        }
        return ans;
    }
    
    string change (string t,int s)
    {   
         string a(t);
        if (s == 1)
         {
             for(int i=N-1;i>=0;--i)
               a[N-i-1] = t[i];
         }
        else if (s == 2)
        {    
              a[0] = t[3];
              a[7] = t[4];
              int v = 1;
           for (int i=0;i<N;++i)
             {
                 if (i==3 || i == 4) continue;
                 a[v++] = t[i];
             }
        }
        else
         {
           char s1 = t[1];char s2 = t[2];
           char s5 = t[5];char s6 = t[6];
           a[2] = s1; a[5] = s2;a[6] = s5; a[1]=s6;
         }
        return a;
    }
    
    void bfs()
    {  
       node temp ;
       string s;
       int v;
      while(!qu.empty())
       {
            temp = qu.front();qu.pop();
            for (int i=1;i<=3;++i) // A,B,C
             {
                  s = change(temp.st,i);
                  v =kt(s);
                 if(dis[v].num == -1)
              {
                  node t ;t.st = s;t.num = v;
                  qu.push(t);
                  dis[v].num = temp.num;dis[v].c =i;
              } 
             }
       }
    }
    void putans()
    {
       char ans[MAX];
       int i = 0;
       int j = Tflag;
       while(j!= q)
       {
           ans[i++] = dis[j].c+'A'-1;
        j = dis[j].num;
       }    
       for (int j = i-1;j>=0;--j)
         printf ("%c",ans[j]);
         printf ("
    ");
    } 
    
     int main ()
     {    
           str = "12345678";
           char s1[10];
           q = kt(str);
           node t ;t.st = str;t.num = q;
           qu.push(t);
           bfs();  //打表预处理,从12345678 到其他态的路径算出 
       while(cin>>str>>Tstr)
        { 
    //利用一种映射关系 将 起始映射为12345678 对应的终态也就映射成另一个了
    //然后就可以查询了(比如 23456781 -- 12345678的映射,就是,2对应1,3对应2...)
            //映射
            for (int i=0;i<N;++i)
               s1[str[i]-'0'] = i+1; //这里,s1 数组就相当于一个函数了,来映射 
            for (int i=0;i<N;++i)
               Tstr[i] = s1[Tstr[i]-'0'] +'0';
            Tflag = kt(Tstr);
            putans();
        } 
        
      return 0;
    }/*
    63728145
    86372541
    */ 
  • 相关阅读:
    shell script
    Shell相关
    Linux文件目录磁盘基本知识
    Linux基础
    Spring事务
    跨域问题
    Ubuntu18.04安装MySQL
    如何掌握 Spring,Spring Boot 全家桶?系统学习 Spring 的大纲一份(实战教学)
    【问题解决】vim 打开文档后提醒 E325: ATTENTION 怎么办?
    vi 中按了 Ctrl+S 后死机不能动怎么办?
  • 原文地址:https://www.cnblogs.com/yuluoluo/p/8635461.html
Copyright © 2011-2022 走看看