上课听到旁边同学在讨论这道题,说是要用康托展开,虽然我不是太懂,但是回去也搜了一下优化方法,然后就发现了另一个方法,在启发下完成了这道题~(虽然说是启发#_#,毕竟很菜,至少这算是第一步吧~)
#include <iostream>
#include <stdlib.h>
#include <list>
using namespace std;
/*
Reference:
C语言的循环右移
http://wenku.baidu.com/link?url=o3AdYdqE-FpR2CidnfxJNGqpi_QzK226C7pFENqYFjsA1bceTH4RodGW1T7NIeYSi701s6ukwDHGQ-BZzBeuhbpIyPKHuphv2i9s5OmmbhO
http://logic0.blog.163.com/blog/static/1889281462009910943135/
*/
/*
思想:1.将状态压缩储存,由于共有8种不同状态,所以可以用3位0,1表示。
注意:状态{1, 2, 3, 4, 8, 7, 6, 5}储存为{100, 101, 110, 111, 011, 010, 001, 000},模拟内存储存方式,高位存高位,低位存低位。共有2^24种可能,大约16M。
2.压缩储存后,A, B, C操作均用位操作完成。B中十进制的循环右移需改成循环左移。
3.由于注意到ABC三操作的特殊性,可以用哈希表储存,并不断通过等式:
1) A(A(i)) = i; 2) B(B(B(B(i)))) = i; 3)C(C(C(C(i)))) = i;
回溯父状态,加入操作队列。
*/
char hashtable[1<<24];
int initial[8] = {1, 2, 3, 4, 8, 7, 6, 5};
int opA(int n) {
// 4095 = (111111111111)B 用来截断24(8*3)位的后12位,先左移12位,再将剩下的右移12位,两者取或
// 用来实现A操作交换上下行的功能
return (n & 4095) << 12 | n >> 12;
}
// 注意,在原十进制形式下的循环右移,由于储存方式不同(低位低字节,高位高字节)
// 变为循环左移,这是我遇到的问题之一
int opB(int n) {
int s = n;
int t = n;
// 截取后12位
s = (s & 4095) ;
// 后12位的循环左移
s = ((s << 3) | (s >> 9)) & 4095 ;
// 截取前12位
t = (t & (4095 << 12));
// 前12位的循环左移
t = t >> 12;
t = ((t << 3) | (t >> 9)) & 4095;
t = (t << 12) & (4095 << 12);
return t | s;
}
int opC(int n) {
int tmp;
// 取出相应位置的四位数,将相应位置留白
tmp = n & (~0x1f81f8);
// 对四位数进行变换
// 先取第一排第二个
int a = ( n & 0x1c0000 ) >> 3;
// 第一排第二个
int b = (n & 0x38000) >> 12;
// 第二排第一个
int c = (n & 0x1c0) << 12;
// 第二排第二个
int d = (n & 0x38) << 3;
return tmp | a | b | c | d;
}
int generate(int a[]) {
int s = 0;
// 将每位数放到正确的位置储存
for(int i = 0; i < 8; i++) {
s |= (a[i] - 1) << (3 * i);
}
return s;
}
int main() {
int i,j,k;
int final[8];
int begin = generate(initial);
list<int> bfs;
hashtable[begin] = 'E';
// 宽度优先搜索
bfs.push_back(begin);
while(!bfs.empty()) {
i = bfs.front();
bfs.pop_front();
j = opA(i);
// A操作压栈
if(!hashtable[j]) {
hashtable[j] = 'A';
bfs.push_back(j);
}
j = opB(i);
// B操作压栈
if(!hashtable[j]) {
hashtable[j] = 'B';
bfs.push_back(j);
}
j = opC(i);
// C操作压栈
if(!hashtable[j]) {
hashtable[j] = 'C';
bfs.push_back(j);
}
}
char operations[250];
while(cin >> k && k != -1) {
for(i = 0; i < 8; i++) cin >> final[i];
j = 0;
for(i = generate(final); i != begin; ++j) {
// 从终止状态向上回溯
operations[j] = hashtable[i];
switch(operations[j]) {
// operations[]储存的是已对j做的一次操作,所以以下2, 4, 4循环
// 次数均要减1
case 'A': i = opA(i);
break;
case 'B': i = opB(opB(opB(i)));
break;
case 'C': i = opC(opC(opC(i)));
break;
}
}
if(j > k) cout << "-1" << endl;
else {
cout << j << " ";
while(j--) cout << operations[j];
cout << endl;
}
}
return 0;
}