http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2477
最大深度只有5层, 用IDA* 算法, 这题的亮点就是用数组来预处理模方的每种旋转,节约时间和代码量 。
h函数的选择: 因为无论怎么旋转,每块魔方的中间位置的颜色是不会变的,因此可以用总共不在原来面上的方块数来作为h函数。 每次旋转,最多能使12块魔方回到原来的面上。
代码:
/* ZOJ 2477 Magic Cube Tips : IDA* runtime 0ms Memory : 180K */ #include<stdio.h> #include<string.h> using namespace std; int T,deep; char s[60] ; int cent[7] = {5,23,26,29,32,50} ; int ex[7][9] = {{1,2,3,4,6,7,8,9}, {10,11,12,22,24,34,35,36}, {13,14,15,25,27,37,38,39}, {16,17,18,28,30,40,41,42}, {19,20,21,31,33,43,44,45}, {46,47,48,49,51,52,53,54} } ; int get_h(){ int res = 0 ; for(int i=0;i<6;i++){ int c = 0 ; for(int j=0;j<8;j++){ if(s[ex[i][j]]!=s[cent[i]]) c++ ; } res += c ; } return res ; } int wh[10], dd[10] ; /* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 */ int ope[12][20] = { //用预处理的数组来代替每一种旋转,节约时间。 {1,4,7,13,25,37,46,49,52,21,33,45,10,11,12,24,36,35,34,22}, {45,33,21,1,4,7,13,25,37,52,49,46,34,22,10,11,12,24,36,35}, {7,8,9,16,28,40,48,47,46,36,24,12,13,14,15,27,39,38,37,25}, {36,24,12,7,8,9,16,28,40,48,47,46,37,25,13,14,15,27,39,38}, {9,6,3,19,31,43,54,51,48,39,27,15,16,17,18,30,42,41,40,28}, {39,27,15,9,6,3,19,31,43,54,51,48,40,28,16,17,18,30,42,41}, {42,30,18,3,2,1,10,22,34,52,53,54,19,20,21,33,45,44,43,31}, {52,53,54,42,30,18,3,2,1,10,22,34,43,31,19,20,21,33,45,44}, {15,14,13,12,11,10,21,20,19,18,17,16,1,2,3,6,9,8,7,4}, {18,17,16,15,14,13,12,11,10,21,20,19,7,4,1,2,3,6,9,8}, {37,38,39,40,41,42,43,44,45,34,35,36,46,47,48,51,54,53,52,49}, {34,35,36,37,38,39,40,41,42,43,44,45,52,49,46,47,48,51,54,53} } ; bool dfs(int d){ char maze[60] ; int h = get_h(); if(d+(h+11)/12 > deep) return false ; if(h==0 && d==deep) return true ; for(int i=0;i<12;i++){ memcpy(maze,s,sizeof(s)); for(int j=0;j<20;j++){ s[ope[i][j]] = maze[ope[i^1][j]]; } wh[d] = i/2 ; if((i&1)==0) dd[d] = 1; else dd[d] = -1 ; if(dfs(d+1)) return true ; memcpy(s,maze,sizeof(maze)); } } void scan(char &c){ char cc ; while(cc=getchar() , cc<'a'||cc>'z') ; c = cc ; } int main(){ //freopen("1in","r",stdin) ; //freopen("1out","w",stdout); scanf("%d",&T); while(T--){ for(int i=1;i<=54;i++){ scan(s[i]); } if(get_h() == 0){ printf("0\n") ; continue ; } deep = 1 ; while(deep <= 5){ if(dfs(0)) break ; deep ++ ; } if(deep > 5){ printf("-1\n"); } else{ printf("%d\n",deep); for(int i=0;i<deep;i++){ printf("%d %d\n",wh[i],dd[i]) ; } } } return 0; }