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
给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。
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
由于刚做完八数码问题,再来做这题,认为非常简单。可是用bfs超时(原因是多组数据,太多的数据将程序拖到超时),用dbfs就一直wa(原来是反向的搜索不能保证后半段的字典序最小,只能保证后半段的逆序的字典序最小),所以就得不到正确结果。
百度了一下,原来使用映射+bfs预处理的方法解决的,这样,再多组数据也不怕了。
将任意的初始状态映射为12345678,在这个过程中得到一个映射函数,目标状态根据这个映射函数,映射为相应的目标状态。(这样子能得到正确答案的原因是,魔板的变换,其实只是位置的变换,数字只是用来标记位置的而已,通过同一种映射关系将初始和目标状态的标记同时该改变,所以仍然能得到正确答案)
那么所有的数据,都能转化为初始状态为12345678的搜索,那么只要一遍bfs搜索出12345678所有能到达的状态,并记录步骤即可。
1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #include <string> 5 #include <iostream> 6 using namespace std; 7 char st[9],ed[9]; 8 int vis[55555]; 9 string ans[55555]; 10 int fac[10] = {1,1,2,6,24,120,720,5040,40320}; 11 int getHash(char *str)//康托展开 12 { 13 int i,j,hash = 0,cnt; 14 for(i=0; i<8; ++i) 15 { 16 cnt = 0; 17 for(j=i+1; j<8; ++j) 18 if(str[j]<str[i]) 19 cnt++; 20 hash += cnt * fac[8-i-1]; 21 } 22 return hash; 23 } 24 struct node 25 { 26 char str[8]; 27 }; 28 int d[3][8] = {{7,6,5,4,3,2,1,0},{3,0,1,2,5,6,7,4},{0,6,1,3,4,2,5,7}}; 29 char change[8]; 30 31 void bfs() 32 { 33 queue<node> q; 34 node cur,tmp; 35 int i,j; 36 for(i=0; i<8; ++i) 37 cur.str[i] = i + '1'; 38 int hash = getHash(cur.str); 39 q.push(cur); 40 vis[hash] = true; 41 q.push(cur); 42 while(!q.empty()) 43 { 44 cur = q.front(); q.pop(); 45 int pHash = getHash(cur.str); 46 for(i=0; i<3; ++i) 47 { 48 for(j=0; j<8; ++j) 49 tmp.str[j] = cur.str[d[i][j]]; 50 hash = getHash(tmp.str); 51 if(vis[hash]) continue; 52 vis[hash] = true; 53 ans[hash] = ans[pHash] + (char)('A' + i); 54 q.push(tmp); 55 } 56 } 57 } 58 59 60 int main() 61 { 62 bfs(); 63 int i; 64 while(scanf("%s%s",st,ed)!=EOF) 65 { 66 for(i=0; i<8; ++i) 67 change[st[i]-'1'] = i+'1';//得到映射函数 68 for(i=0; i<8; ++i) 69 ed[i] = change[ed[i]-'1'];//根据映射函数改变目标状态 70 int hash = getHash(ed); 71 cout<<ans[hash]<<endl; 72 } 73 return 0; 74 }