HDU - 1430 - 魔板( 康托展开 + BFS预处理 )
Posted alphakin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 1430 - 魔板( 康托展开 + BFS预处理 )相关的知识,希望对你有一定的参考价值。
魔板
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4242 Accepted Submission(s): 1011
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
----------------------------------------------------------------------------------------------------------------------------
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1430
直接BFS + 康托去重会TLE。
双向BFS会遇到反向BFS时处理字典序最小的问题。
简单的方法:
先以 " 12345678 " 为初始状态进行bfs,将并所有情况保存下来,这样可以从" 12345678 "到达任何一种情况。
但是,出状态不一定是" 12345678 ",所以我们可以进行映射。
例如:
初状态:4 6 2 8 5 7 3 1
末状态:3 4 8 7 2 5 1 6
可以转换成:
初状态:1 2 3 4 5 6 7 8
末状态:7 1 4 6 3 5 8 2
那么从 " 46285731 " 到 " 34872516 " 的路径 就等于 从 " 1234578 " 到 " 71463582 " 的路径。
而 " 1234578 " 到 " 71463582 " 的路径我们已经记录下来,直接递归打印出结果。
( 答案为: BCBCBCABCABCABBCCBCB )
*数据里有初状态和末状态相等的情况,直接输出换行即可。
附AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <queue> 6 #define SIZE 40325 7 using namespace std; 8 9 const int fac[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; 10 struct ref{ 11 int parent; 12 char op; 13 }ans[SIZE]; 14 15 struct node{ 16 char s[10]; 17 int value; 18 node(){} 19 node(char * ss, const int v) : value(v){ 20 for(int i=0; i<8; ++i) *(s + i) = *(ss + i); 21 } 22 }; 23 24 bool vis[SIZE] = {0}; 25 int cantor(char * s){ 26 bool vis[10] = {0}; 27 int rec, ans = 0; 28 for(int i=0; i<8; ++i){ 29 vis[s[i]] = 1, rec = 0; 30 for(int j=1; j<s[i]; ++j) 31 if(!vis[j]) ++rec; 32 ans += rec * fac[7 - i]; 33 } 34 return ans + 1; 35 } 36 37 void swap(char * s, const int posa, const int posb){ 38 char tmp = *(s + posa); 39 *(s + posa) = *(s + posb); 40 *(s + posb) = tmp; 41 } 42 43 void operate(char * s, const char type){ 44 if(type == 0){ for(int i=0; i<4; ++i) swap(s, i, 7-i); } 45 else if(type == 1) for(int i=0; i<3; ++i) swap(s, i, 3), swap(s, 4, 7 - i); 46 else { swap(s, 2, 5); swap(s, 1, 2); swap(s, 1, 6); } 47 } 48 49 void bfs(){ 50 int value, k = 0; 51 node begin, now, next; 52 for(int i=0; i<8; ++i) begin.s[i] = i+1; 53 begin.value = cantor(begin.s); 54 queue<node> q; 55 q.push(begin); 56 int rec = 0; 57 while(q.size()){ 58 now = q.front(); q.pop(); 59 for(int i=0; i<3; ++i){ 60 next = now; 61 operate(next.s, i); 62 if(!vis[ value = cantor(next.s) ]){ 63 vis[value] = 1; 64 q.push(node(next.s, value)); 65 ans[value].parent = now.value; 66 ans[value].op = ‘A‘ + i; 67 } 68 } 69 } 70 } 71 72 void deal(const int pos){ 73 if(ans[pos].parent == 1){ 74 putchar(ans[pos].op); 75 return; 76 } 77 deal(ans[pos].parent); 78 putchar(ans[pos].op); 79 } 80 81 void reflect(char * s, char * e){ 82 char reca[8], recb[8], ss[8]; 83 for(int i=0; i<8; ++i){ 84 reca[s[i]-1] = i, recb[e[i]-1] = i; 85 } 86 for(int i=0; i<8; ++i){ 87 *(e + recb[i]) = reca[i] + 1; 88 } 89 } 90 91 int main(){ 92 //freopen("in", "r", stdin); 93 char str[10], ptr[10]; 94 bfs(); 95 while(~scanf("%s%s", str, ptr)){ 96 if(!strcmp(str, ptr)){ 97 putchar(‘ ‘); 98 continue; 99 } 100 for(int i=0; i<8; ++i) str[i] -= ‘0‘, ptr[i] -= ‘0‘; 101 reflect(str, ptr); 102 deal(cantor(ptr)); 103 putchar(‘ ‘); 104 } 105 return 0; 106 }
以上是关于HDU - 1430 - 魔板( 康托展开 + BFS预处理 )的主要内容,如果未能解决你的问题,请参考以下文章