在魔方风靡全球之后不久,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
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N = 8;
queue <LL> que;
string ans[50000];
char str1[10], str2[10];
bool vis[50000];
int map[10];//映射
int num[10];
LL fac[N];//阶乘
void change(int s[], int o){//o分别是0,1,2,表示ABC三种变化
switch(o){
case 0:
for(int i = 0; i < 4; i ++) swap(s[i], s[8-i-1]);
break;
case 1:
for(int i = 3; i >= 1; i --) swap(s[i], s[i-1]);
for(int i = 4; i < 7; i ++) swap(s[i], s[i+1]);
break;
case 2:
swap(s[1], s[6]);
swap(s[6], s[5]);
swap(s[5], s[2]);
break;
}
}
void cantor(int s[], LL num, int k){//康托展开,把一个数字num展开成一个数组s,k是数组长度
int t;
bool h[k];//0到k-1,表示是否出现过
memset(h, 0, sizeof(h));
for(int i = 0; i < k; i ++){
t = num / fac[k-i-1];
num = num % fac[k-i-1];
for(int j = 0, pos = 0; ; j ++, pos ++){
if(h[pos]) j --;
if(j == t){
h[pos] = true;
s[i] = pos + 1;
break;
}
}
}
}
void inv_cantor(int s[], LL &num, int k){//康托逆展开,把一个数组s换算成一个数字num
int cnt;
num = 0;
for(int i = 0; i < k; i ++){
cnt = 0;
for(int j = i + 1; j < k; j ++){
if(s[i] > s[j]) cnt ++;//判断几个数小于它
}
num += fac[k-i-1] * cnt;
}
}
void init(){
fac[0] = 1;
for(int i = 1; i < N; i ++) fac[i] = fac[i-1] * i;
int a[8], b[8];
LL temp, temp2;
que.push(0);
vis[0] = true;
while(!que.empty()){
LL temp = que.front(); que.pop();
cantor(a, temp, 8);
for(int i = 0; i < 3; i ++){
copy(a, a+8, b);
change(b, i);
inv_cantor(b, temp2, 8);
if(!vis[temp2]){
que.push(temp2);
vis[temp2] = true;
ans[temp2] = ans[temp] + (char)('A' + i);
}
}
}
}
int main(){
init();
while(~scanf("%s", str1)){
scanf("%s", str2);
//先把所有初始状态都转换成12345678
//最终状态根据初始状态的转换而转换
//这样只要一次预处理就可以解决问题了
for(int i = 0; i < 8; i ++) map[str1[i] - '0'] = i + 1;
for(int i = 0; i < 8; i ++) num[i] = map[str2[i] - '0'];
LL temp;
inv_cantor(num, temp, 8);
cout << ans[temp] << endl;
}
}