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
----------------------------------------------------------------------------------------------------------------------------
直接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代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #define SIZE 40325 using namespace std; const int fac[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; struct ref{ int parent; char op; }ans[SIZE]; struct node{ char s[10]; int value; node(){} node(char * ss, const int v) : value(v){ for(int i=0; i<8; ++i) *(s + i) = *(ss + i); } }; bool vis[SIZE] = {0}; int cantor(char * s){ bool vis[10] = {0}; int rec, ans = 0; for(int i=0; i<8; ++i){ vis[s[i]] = 1, rec = 0; for(int j=1; j<s[i]; ++j) if(!vis[j]) ++rec; ans += rec * fac[7 - i]; } return ans + 1; } void swap(char * s, const int posa, const int posb){ char tmp = *(s + posa); *(s + posa) = *(s + posb); *(s + posb) = tmp; } void operate(char * s, const char type){ if(type == 0){ for(int i=0; i<4; ++i) swap(s, i, 7-i); } else if(type == 1) for(int i=0; i<3; ++i) swap(s, i, 3), swap(s, 4, 7 - i); else { swap(s, 2, 5); swap(s, 1, 2); swap(s, 1, 6); } } void bfs(){ int value, k = 0; node begin, now, next; for(int i=0; i<8; ++i) begin.s[i] = i+1; begin.value = cantor(begin.s); queue<node> q; q.push(begin); int rec = 0; while(q.size()){ now = q.front(); q.pop(); for(int i=0; i<3; ++i){ next = now; operate(next.s, i); if(!vis[ value = cantor(next.s) ]){ vis[value] = 1; q.push(node(next.s, value)); ans[value].parent = now.value; ans[value].op = 'A' + i; } } } } void deal(const int pos){ if(ans[pos].parent == 1){ putchar(ans[pos].op); return; } deal(ans[pos].parent); putchar(ans[pos].op); } void reflect(char * s, char * e){ char reca[8], recb[8], ss[8]; for(int i=0; i<8; ++i){ reca[s[i]-1] = i, recb[e[i]-1] = i; } for(int i=0; i<8; ++i){ *(e + recb[i]) = reca[i] + 1; } } int main(){ //freopen("in", "r", stdin); char str[10], ptr[10]; bfs(); while(~scanf("%s%s", str, ptr)){ if(!strcmp(str, ptr)){ putchar('\n'); continue; } for(int i=0; i<8; ++i) str[i] -= '0', ptr[i] -= '0'; reflect(str, ptr); deal(cantor(ptr)); putchar('\n'); } return 0; }