Following the success of the magic cube, Mr. Rubik invented its planar version, called magic squares. This is a sheet composed of 8 equal-sized squares:
1 | 2 | 3 | 4 |
8 | 7 | 6 | 5 |
In this task we consider the version where each square has a different color. Colors are denoted by the first 8 positive integers. A sheet configuration is given by the sequence of colors obtained by reading the colors of the squares starting at the upper left corner and going in clockwise direction. For instance, the configuration of Figure 3 is given by the sequence (1,2,3,4,5,6,7,8). This configuration is the initial configuration.
Three basic transformations, identified by the letters `A', `B' and `C', can be applied to a sheet:
Below is a demonstration of applying the transformations to the initial squares given above:
A: |
|
B: |
|
C: |
|
All possible configurations are available using the three basic transformations.
You are to write a program that computes a minimal sequence of basic transformations that transforms the initial configuration above to a specific target configuration.
A single line with eight space-separated integers (a permutation of (1..8)) that are the target configuration.
2 6 8 4 5 7 3 1
Line 1: | A single integer that is the length of the shortest transformation sequence. |
Line 2: | The lexically earliest string of transformations expressed as a string of characters, 60 per line except possibly the last line. |
7 BCABCCB
题解:看到此题,果断想到了The Clocks的方法,然后速度写了个DFS,写完才发现步数要最短(以后还是要认真看题呀,这次就是教训!!!),所以我就记录了一下最优解。不过深度达到15就超时了。。。只能推到重来,用BFS写。当然肯定要判重,减少拓展节点,避免重复拓展同一状态,不然还是得超时,如果开个87654321大的hash数组会超内存,所以这样还是行不通,只好去看题解,题解上是用康托展开。所以我就去学习了下康托展开。主要看的是网友morgan_xww写的这篇文章,果断当个搬运工,嘿嘿。
康托展开:
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai为整数,并且0<=ai<i(1<=i<=n)
应用实例:
{1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个?
如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321。想知道321是{1,2,3}中第几个大的数。
这样考虑:第一位是3,小于3的数有1、2 。所以有2*2!个。再看小于第二位,小于2的数只有一个就是1 ,所以有1*1!=1 所以小于32
的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。2*2!+1*1!是康托展开。
再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个,0*3!,第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2,1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数,0*1!,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。
int fac[] = {1,1,2,6,24,120,720,5040,40320}; //i的阶乘为fac[i] /* 康托展开. {1...n}的全排列由小到大有序,s[]为第几个数 */ int KT(int n, int s[]) { int i, j, t, sum; sum = 0; for (i=0; i<n; i++) { t = 0; for (j=i+1; j<n; j++) if (s[j] < s[i]) t++; sum += t*fac[n-i-1]; } return sum+1; }
康托展开的逆运算:
{1,2,3,4,5}的全排列已经从小到大排序,要找出第16个数:
1. 首先用16-1得到15
2. 用15去除4! 得到0余15
3. 用15去除3! 得到2余3
4. 用3去除2! 得到1余1
5. 用1去除1! 得到1余0
有0个数比它小的数是1
所以第一位是1
有2个数比它小的数是3,但1已经在之前出现过了所以是4
有1个数比它小的数是2,但1已经在之前出现过了所以是3
有1个数比它小的数是2,但1,3,4都出现过了所以是5
最后一个数只能是2
所以这个数是14352
/* 康托展开的逆运算. {1...n}的全排列,中的第k个数为s[] */ void invKT(int n, int k, int s[]) { int i, j, t, vst[8]={0}; k--; for (i=0; i<n; i++) { t = k/fac[n-i-1]; for (j=1; j<=n; j++) if (!vst[j]) { if (t == 0) break; t--; } s[i] = j; vst[j] = 1; k %= fac[n-i-1]; } }
本屌实在太弱了,o(╯□╰)o,代码是模仿的%>_<%,当然思路还是理解咯,还学到康托展开这个好东东了,O(∩_∩)O~~,哈哈。
1 /* 2 ID:spcjv51 3 PROG:msquare 4 LANG:C++ 5 */ 6 #include<stdio.h> 7 #include<string.h> 8 #include<stdlib.h> 9 struct que 10 { 11 int len; 12 char ch; 13 long pre; 14 int s[8]; 15 } q[50000]; 16 int fac[8]={1,1,2,6,24,120,720,5040}; 17 int hash[50000],goal[8]; 18 int check(struct que *x) 19 { 20 int i; 21 for(i=0; i<8; i++) 22 if(x->s[i]!=goal[i]) return 0; 23 return 1; 24 } 25 long cotor(struct que *x) 26 { 27 long i,j,t,sum; 28 sum=0; 29 for(i=0; i<8; i++) 30 { 31 t=0; 32 for(j=i+1; j<8; j++) 33 if(x->s[j]<x->s[i]) 34 t++; 35 sum+=t*fac[7-i]; 36 } 37 return sum+1; 38 } 39 void swap(int *a,int *b) 40 { 41 int temp; 42 temp=*a; 43 *a=*b; 44 *b=temp; 45 } 46 void print(int k) 47 { 48 int i,j,r; 49 char s[100]; 50 printf("%d\n",q[k].len); 51 i=0; 52 while(q[k].len) 53 { 54 s[i++]=q[k].ch; 55 k=q[k].pre; 56 } 57 r=0; 58 for(j=i-1;j>=0;j--) 59 { 60 r++; 61 printf("%c",s[j]); 62 if(r%60==0) printf("\n"); 63 } 64 printf("\n"); 65 } 66 void BFS() 67 { 68 long tail,head,i,t; 69 struct que temp; 70 hash[cotor(&q[0])]=1; 71 head=0; 72 tail=1; 73 q[0].len=0; 74 while(head<tail) 75 { 76 temp=q[head]; 77 for(i=0; i<4; i++) swap(&temp.s[i],&temp.s[7-i]); 78 t=cotor(&temp); 79 if(!hash[t]) 80 { 81 q[tail]=temp; 82 q[tail].len=q[head].len+1; 83 q[tail].ch='A'; 84 q[tail].pre=head; 85 hash[t]=1; 86 if(check(&q[tail])) break; 87 tail++; 88 } 89 temp=q[head]; 90 swap(&temp.s[0],&temp.s[3]); 91 swap(&temp.s[4],&temp.s[7]); 92 swap(&temp.s[1],&temp.s[3]); 93 swap(&temp.s[2],&temp.s[3]); 94 swap(&temp.s[4],&temp.s[6]); 95 swap(&temp.s[4],&temp.s[5]); 96 t=cotor(&temp); 97 if(!hash[t]) 98 { 99 q[tail]=temp; 100 q[tail].len=q[head].len+1; 101 q[tail].ch='B'; 102 q[tail].pre=head; 103 hash[t]=1; 104 if(check(&q[tail])) break; 105 tail++; 106 } 107 temp=q[head]; 108 swap(&temp.s[1],&temp.s[2]); 109 swap(&temp.s[5],&temp.s[6]); 110 swap(&temp.s[1],&temp.s[5]); 111 t=cotor(&temp); 112 if(!hash[t]) 113 { 114 q[tail]=temp; 115 q[tail].len=q[head].len+1; 116 q[tail].ch='C'; 117 q[tail].pre=head; 118 hash[t]=1; 119 if(check(&q[tail])) break; 120 tail++; 121 } 122 head++; 123 } 124 print(tail); 125 126 } 127 int main(void) 128 { 129 freopen("msquare.in","r",stdin); 130 freopen("msquare.out","w",stdout); 131 int i; 132 for(i=0; i<8; i++) 133 { 134 scanf("%d",&goal[i]); 135 q[0].s[i]=i+1; 136 } 137 memset(hash,0,sizeof(hash)); 138 if(check(&q[0])) 139 printf("0\n\n"); 140 else 141 BFS(); 142 return 0; 143 }