题目背景
在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有8个大小相同的格子的魔板:
1 2 3 4
8 7 6 5
题目描述
我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示。这是基本状态。
这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改变魔板的状态):
“A”:交换上下两行;
“B”:将最右边的一列插入最左边;
“C”:魔板中央四格作顺时针旋转。
下面是对基本状态进行操作的示范:
A: 8 7 6 5
1 2 3 4
B: 4 1 2 3
5 8 7 6
C: 1 7 2 4
8 6 3 5
对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。
输入格式
只有一行,包括8个整数,用空格分开(这些整数在范围 1——8 之间)不换行,表示目标状态。
输出格式
Line 1: 包括一个整数,表示最短操作序列的长度。
Line 2: 在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。
1 /* 2 如何判断重复状态??如果每一位枚举的话就太慢了,而且耗空间; 3 那么可不可以用八进制数来存呢?也不行,这样数组开的太大,会爆空间; 4 于是我们用康托展开,康托就是某数所在全排列中的排序 5 bfs少不了queue啦 6 这里queue存的是上一状态的编号,这里另外使用了一个编号 7 然后枚举三种操作,判断去重后,记录他的编号,上一状态编号,当前状态步数以及达到当前状态的操作,加入队列即可 8 最后达到目标状态递归输出即可 9 */ 10 #include<cstdio> 11 #include<queue> 12 using namespace std; 13 struct node 14 { 15 int a[3][5]; 16 }start,goal,c[500005]; 17 int goalnum,startnum; 18 int v[500005]; 19 int jc[9] = {1,1,2,6,24,120,720,5040,423360}; 20 int step[500005],fa[500005],cnt,op[500005]; 21 queue< int>q; 22 int kangtuo(node x) 23 { 24 int res = 0; 25 int mid[9]; 26 for(int i = 1;i <= 4;i ++)mid[i] = x.a[1][i]; 27 for(int i = 4;i >= 1;i --)mid[9 - i] = x.a[2][i]; 28 for(int i = 1;i <= 8;i ++) 29 { 30 int midres = 0; 31 for(int j = i + 1;j <= 8;j ++) 32 { 33 if(mid[j] < mid[i]) 34 { 35 midres ++; 36 } 37 } 38 res += midres * jc[8 - i]; 39 } 40 return res; 41 } 42 node change(int k,int u) 43 { 44 node res; 45 if(k == 1) 46 { 47 for(int i = 1;i <= 4;i ++)res.a[2][i] = c[u].a[1][i]; 48 for(int i = 1;i <= 4;i ++)res.a[1][i] = c[u].a[2][i]; 49 } 50 else if(k == 2) 51 { 52 res.a[1][1] = c[u].a[1][4];res.a[2][1] = c[u].a[2][4]; 53 for(int i = 2;i <= 4;i ++)res.a[1][i] = c[u].a[1][i - 1]; 54 for(int i = 2;i <= 4;i ++)res.a[2][i] = c[u].a[2][i - 1]; 55 } 56 else if(k == 3) 57 { 58 res = c[u]; 59 res.a[1][2] = c[u].a[2][2]; 60 res.a[1][3] = c[u].a[1][2]; 61 res.a[2][3] = c[u].a[1][3]; 62 res.a[2][2] = c[u].a[2][3]; 63 } 64 return res; 65 } 66 void print(int x) 67 { 68 if(x == 1)return ; 69 print(fa[x]); 70 if(op[x] == 1)printf("A"); 71 else if(op[x] == 2)printf("B"); 72 else if(op[x] == 3)printf("C"); 73 } 74 void bfs() 75 { 76 while(!q.empty()) 77 { 78 int u = q.front(); 79 q.pop(); 80 for(int i = 1;i <= 3;i ++) 81 { 82 node too = change(i,u); 83 int midnum = kangtuo(too); 84 if(!v[midnum]) 85 { 86 v[midnum] = 1; 87 c[++cnt] = too;//别忘了++cnt啊 88 fa[cnt] = u; 89 step[cnt] = step[u] + 1; 90 op[cnt] = i; 91 if(midnum == goalnum)//这里判断会节省几步 92 { 93 printf("%d ",step[cnt]); 94 print(cnt); 95 return ; 96 } 97 q.push(cnt); 98 } 99 } 100 } 101 } 102 int main() 103 { 104 for(int i = 1;i <= 4;i ++)start.a[1][i] = i; 105 for(int i = 4;i >= 1;i --)start.a[2][i] = 9 - i; 106 for(int i = 1;i <= 4;i ++)scanf("%d",&goal.a[1][i]); 107 for(int i = 4;i >= 1;i --)scanf("%d",&goal.a[2][i]); 108 startnum = kangtuo(start); 109 v[startnum] = 1; 110 goalnum = kangtuo(goal); 111 if(startnum == goalnum) 112 { 113 printf("0"); 114 return 0; 115 } 116 c[++cnt] = start; 117 step[cnt] = 0; 118 fa[cnt] = cnt; 119 op[cnt] = 0; 120 q.push(1); 121 bfs(); 122 return 0; 123 }