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

    魔板

    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分别表示。任一时刻魔板的状态可用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,所得到的数字序列即可表示此时魔板的状态。例如,序列(1,2,3,4,5,6,7,8)表示魔板状态为:

    1 2 3 4
    8 7 6 5

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

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

    给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。
     
    Input
    每组测试数据包括两行,分别代表魔板的初态与目态。
     
    Output
    对每组测试数据输出满足题意的变换步骤。
     
    Sample Input
    12345678
    17245368
    12345678
    82754631
     
    Sample Output
    C
    AC
     
    Author
    LL
     
    Source
     
    Recommend
    linle   |   We have carefully selected several similar problems for you:  1429 1426 1427 1401 1043 
     
    第一眼看到这道题,只想到了爆搜的方法,但是这是个八位数,直接标记数字无法进行下去,于是我天真地将其分成两个四位数分开标记,最后当然是华丽的超时。。。。看着眼前欲哭无泪的代码,我决定上网看看各路大神的写法,结果找到了一个貌似很厉害的东东,“康托展开”(详见我的另一篇博客“康托展开”),仔细研究了一番,发现很有道理的样纸,于是仿照网上的代码,完成了自己的。
    起始状态ch1虽然不是12345678,但是可以把它看做12345678(状态ss),因而就有一种对应关系存在,用这种对应关系置换最终状态ch2得到状态ch,那么原来ch1->ch2就可以等价为ss->ch了。这样就只需要对ss这个状态进行一次bfs预处理,将答案存下来就ok了。
     
    题意:中文题,很好理解。
     
    附上代码:
     
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <string>
      5 #include <queue>
      6 #define MAX 50000
      7 using namespace std;
      8 char ch1[10],ch2[10];
      9 bool vis[MAX];   //标记是否出现过这个串
     10 string str[MAX];   //记录最终的变换过程
     11 int f[10]= {1,1,2,6,24,120,720,5040}; //1-7的阶层,康托展开需要用到
     12 
     13 struct node
     14 {
     15     int t;  //记录康托值
     16     char a[10];  //当前的字符串
     17 } s1,s2;
     18 
     19 void getss(int k)   //三种不同的变换规律
     20 {
     21     int i,j;
     22     if(k==0)
     23     {
     24         for(i=0; i<4; i++)
     25         {
     26             s2.a[i]=s1.a[7-i];
     27             s2.a[i+4]=s1.a[3-i];
     28         }
     29     }
     30     else if(k==1)
     31     {
     32         s2.a[0]=s1.a[3];
     33         s2.a[7]=s1.a[4];
     34         for(i=1; i<4; i++)
     35         {
     36             s2.a[i]=s1.a[i-1];
     37             s2.a[i+3]=s1.a[i+4];
     38         }
     39     }
     40     else
     41     {
     42         for(i=0; i<8; i++)
     43             s2.a[i]=s1.a[i];
     44         s2.a[1]=s1.a[6];
     45         s2.a[2]=s1.a[1];
     46         s2.a[5]=s1.a[2];
     47         s2.a[6]=s1.a[5];
     48     }
     49 }
     50 
     51 int xx(char ss[])   //计算康托展开的数字,方法详见“康托展开”博客
     52 {
     53     int i,j,s=0,w;
     54     for(i=0; i<8; i++)
     55     {
     56         w=0;
     57         for(j=i+1; j<8; j++)
     58             if(ss[j]<ss[i])
     59                 w++;
     60         s+=w*f[7-i];
     61     }
     62     return s;
     63 }
     64 
     65 void BFS()   //预处理
     66 {
     67     queue<node> q;
     68     while(!q.empty())
     69         q.pop();
     70     int i,j,n;
     71     char c;
     72     memset(vis,0,sizeof(vis));   //开始所有的数字为0
     73     s1.t=0;    //康托值为0
     74     strcpy(s1.a,"12345678");   //原始数据为12345678
     75     vis[0]=1;    //出现过则标为1
     76     str[0]="";
     77     q.push(s1);   //进入队列
     78     while(!q.empty())
     79     {
     80         s1=q.front();
     81         q.pop();
     82         for(i=0; i<3; i++)
     83         {
     84             getss(i);   //变换后的字符记录在s2.a上
     85             n=xx(s2.a);  //此时的康托值
     86             if(!vis[n])  //通过判断康托值是否出现以此记录这个串是否出现
     87             {
     88                 vis[n]=1;   //这个康托值标记为已出现
     89                 c='A'+i;    //变换的方案
     90                 s2.t=n;     //保存当前串的康托值
     91                 str[n]=str[s1.t]+c;   //记录变换过程
     92                 q.push(s2);
     93             }
     94         }
     95     }
     96 }
     97 
     98 int main()
     99 {
    100     int i,j,s;
    101     char ch[10];
    102     BFS();       //预处理打表
    103     while(~scanf("%s %s",ch1,ch2))
    104     {
    105         for(i=0; i<8; i++)   //建立对应关系,记录起始数据每个数的位置
    106             ch[ch1[i]-'0']=i+1+'0';
    107         for(i=0; i<8; i++)   //置换,利用位置变换形成新的字符串
    108             ch2[i]=ch[ch2[i]-'0'];
    109         s=xx(ch2);      //计算康托展开的数
    110         cout<<str[s]<<endl;   //根据康托展开记录的数字查找
    111     }
    112     return 0;
    113 }
  • 相关阅读:
    个人工作总结2
    个人工作总结1
    《梦断代码》阅读笔记01
    构建之法阅读笔记4
    四则运算-安卓版
    最大联通子数组之和(dfs,记忆化搜索,状态压缩)
    第五周进度报告
    第四周进度报告
    最大子数列之和问题
    构建之法阅读笔记3
  • 原文地址:https://www.cnblogs.com/pshw/p/4915385.html
Copyright © 2011-2022 走看看