题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430 , 一道比较好的题。
这道题要用到很多知识,康托展开、BFS、打表的预处理还要用到一一映射,做完受益匪浅。
其实这道题也可以用双向BFS来写,思路也已经有了,过几天再来写。
本文持续更新。
先说搜索部分:
对于魔板的每一个状态,都可以进行A、B、C三种操作,所以按照图论来讲,就是操作前的状态可以到达操作后的状态,所以就这样转换成了广搜问题。
这里要注意一点,由于题目要求字典序最小的,所以搜索的时候要按照ABC的顺序来。
再说康托展开:
康托展开其实就是哈希的一种,即用一个数字来表示一个排列。比如说{A , B , C , D}的全排列中,ABCD对应的康托展开的值为0,ABDC对应的康托展开值为1...
关于康托展开算法,具体见:http://www.cnblogs.com/mhpp/p/8039879.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”到映射后的目标状态的步骤的问题,这时按照存好的路径输出即可。
BFS + 打表:
1 #include <iostream> 2 #include <queue> 3 #include <string> 4 #include <string.h> 5 using namespace std; 6 7 const int maxn = 50000 + 5; 8 int vis[maxn]; 9 string ans[maxn]; 10 int fac[]={1 , 1 , 2 , 6 , 24 , 120 , 720 , 5040 , 40320};//1!,2!...8! 11 int Cantor(string str)//康托展开 12 { 13 int ret = 0; 14 int n = str.size(); 15 for(int i = 0 ; i < n ; i++) { 16 int cnt = 0; 17 for(int j = i ; j < n ; j++)//str[i]在子串中是第几大 18 if(str[j] < str[i]) 19 cnt++; 20 ret += cnt * fac[n - i - 1];//累加 21 } 22 return ret; 23 } 24 void move_A(string &str) 25 { 26 for(int i = 0 ; i < 4 ; i++) 27 swap(str[i] , str[7 - i]); 28 } 29 void move_B(string &str) 30 { 31 for(int i = 3 ; i > 0 ; i--) 32 swap(str[i] , str[i - 1]); 33 for(int i = 4 ; i < 7 ; i++) 34 swap(str[i] , str[i + 1]); 35 } 36 void move_C(string &str) 37 { 38 char tmp = str[6]; 39 str[6] = str[5]; 40 str[5] = str[2]; 41 str[2] = str[1]; 42 str[1] = tmp; 43 } 44 void BFS(string str)//预处理,扩张由状态“12345678”,能到的所有状态 45 { 46 memset(vis , 0 , sizeof(vis)); 47 queue <string> que; 48 que.push(str); 49 int x = Cantor(str); 50 vis[x] = 1; 51 ans[x] = ""; 52 while(!que.empty()) { 53 string u = que.front(); 54 que.pop(); 55 int i = Cantor(u); 56 string tmp = u; 57 move_A(tmp); 58 int k = Cantor(tmp); 59 if(!vis[k]) { 60 vis[k] = 1; 61 que.push(tmp); 62 ans[k] = ans[i] + 'A'; 63 } 64 tmp = u; 65 move_B(tmp); 66 k = Cantor(tmp); 67 if(!vis[k]) { 68 vis[k] = 1; 69 que.push(tmp); 70 ans[k] = ans[i] + 'B'; 71 } 72 tmp = u; 73 move_C(tmp); 74 k = Cantor(tmp); 75 if(!vis[k]) { 76 vis[k] = 1; 77 que.push(tmp); 78 ans[k] = ans[i] + 'C'; 79 } 80 } 81 } 82 int main() 83 { 84 int a[10]; 85 string s , e; 86 string start = ("12345678"); 87 BFS(start);//预处理,打表 88 while(cin >> s >> e) 89 { 90 for(int i = 0 ; i < 8 ; i++)//推导开始状态s,到标准开始状态“12345678” 91 //的映射关系,存a中 92 a[s[i] - '0'] = i + 1; 93 for(int i = 0 ; i < 8 ; i++)//由映射关系存a及目标状态e推标准的目标状态。 94 e[i] = a[e[i] - '0'] + '0'; 95 int k = Cantor(e); 96 cout << ans[k] << endl; 97 } 98 return 0; 99 }