这是个简单题。一看就是用队列来BFS,因为1-8八个数字的全排列有8!=40320种。唯一需要解决的问题就是怎么把8个数字的每种不同的排列映射到唯一的整数上,因为如果用一个大小为[87654321]数组,浪费了大量的存储空间,必定导致超内存。找到一个叫“康托展开”的东东,真是惭愧啊,很简单的东西,其实自己应该都能想到才对。很简单的思想:把每种排列映射为该排列在全排列中的次序即可。
/* ID: morgan_xww LANG: C TASK: msquare */ #include <stdio.h> #include <string.h> struct { int vlu; int cnt; int pre; char tsf; } Q[50000]; int fac[9] = {1,1,2,6,24,120,720,5040,40320}; int Target, Qnum, p; char vst[50000]; int KT(int s[]) //康托展开 { int i, j, t, sum; sum = 0; for (i=0; i<8; i++) { t = 0; for (j=i+1; j<8; j++) if (s[j] < s[i]) t++; sum += t*fac[7-i]; } return sum+1; } void invKT(int n, int s[]) //康托展开的逆运算 { int i, j, t, vst[8]={0}; n--; for (i=0; i<8; i++) { t = n/fac[7-i]; for (j=1; j<=8; j++) if (!vst[j]) { if (t == 0) break; t--; } s[i] = j; vst[j] = 1; n %= fac[7-i]; } } void PrintAns() { int i, k; char ans[50000]; k = Qnum-1; printf("%d", Q[k].cnt); i = 0; while (Q[k].cnt) { ans[i++] = Q[k].tsf; k = Q[k].pre; } k = 0; while (--i >= 0) { if (k%60 == 0) printf("/n"); printf("%c", ans[i]); k++; } printf("/n"); exit(0); } void AddQue(int k, char ch) //加入队列 { if (!vst[k]) { Q[Qnum].vlu = k; Q[Qnum].cnt = Q[p].cnt+1; Q[Qnum].pre = p; Q[Qnum].tsf = ch; Qnum++; vst[k] = 1; } if (k == Target) PrintAns(); } void Transf(int s[]) //三种变换 { int i, t[8]; // A变换 for (i=0; i<8; i++) t[i] = s[7-i]; AddQue(KT(t), 'A'); // B变换 t[0] = s[3]; t[7] = s[4]; for (i=1; i<=3; i++) t[i] = s[i-1]; for (i=4; i<=6; i++) t[i] = s[i+1]; AddQue(KT(t), 'B'); // C变换 t[0] = s[1]; s[1] = s[6]; s[6] = s[5]; s[5] = s[2]; s[2] = t[0]; AddQue(KT(s), 'C'); } void BFS() { int s[8]; p = 0; while (p < Qnum) { invKT(Q[p].vlu, s); Transf(s); p++; } } int main() { //freopen("msquare.in", "r", stdin); //freopen("msquare.out", "w", stdout); int i, t; int stat[8]={1,2,3,4,5,6,7,8}; int targ[8]; for (i=0; i<8; i++) scanf("%d", &targ[i]); Target = KT(targ); t = KT(stat); if (t == Target) { printf("0/n/n"); exit(0); } Q[0].vlu = t; Q[0].cnt = 0; Qnum = 1; vst[t] = 1; BFS(); }