题面
This is a very popular game for children. In this game, there's a cube, which consists of 3 * 3 * 3 small cubes. We can unwrap the cube, it will become like this:
w w w
w w w
w w w
r r r g g g b b b o o o
r r r g g g b b b o o o
r r r g g g b b b o o o
y y y
y y y
y y y
The letters means the color on the small cubes. For example, 'r' means red, 'g' means green, 'y' means yellow....The goal for this game is to rotate the faces of the cube to make each of the faces contains only one color. Note there're exact 6 kind of colors on the cube and there're exact 9 small rectangles totally in any time in the game.
Do you know how to rotate the faces? I think most of you have known it. But I would like to show it again. When a face is rotated, the configuration of colors in all the adjacent faces changes. For the cube above, after we rotate the green face clock-wise, the last line of 'w' face will become the left column of 'b' face, the left column of 'b' face will become the top line of 'y' face, etc. As you may know, reaching the final position from a scrambled configuration can be quite challenging.
In this problem, you are given a configuration of the cube, and asked to give a way to reach the final position. To reduce the difficulty, the steps required will never be greater than 5.
Input
The input contains an integer in the first line, which indicates the number of the test cases. In each test case, there're exact 10 lines. The first line is an empty line. The next 9 lines contain a configuration. The format can be seen in the sample input. For simplicity, we give an index to each face as follows:
/---\
| |
| 4 |
| |
/---+---+---+---\
| | | | |
| 0 | 1 | 2 | 3 |
| | | | |
\---+---+---+---/
| |
| 5 |
| |
\---/
Note that there's a space between two adjacent letters.
Output
For each test case, the first line of the output is the smallest count N of the steps to reach the winning position. If the winning position can't be reached in 5 steps, print -1 in this line. Otherwise print each step in one line in the following N lines. A step contains two integers, the first one means the face index, and the second one means the direction. 1 means clock-wise and -1 means counter clock-wise. If the given position is the winning position, print 0 for such test case simply. If there're multiple solutions, any one is acceptable.
Sample Input
2
w w w
w w w
w w w
r r r g g g b b b o o o
r r r g g g b b b o o o
r r r g g g b b b o o o
y y y
y y y
y y y
w w w
w w w
b b b
r r w g g g y b b o o o
r r w g g g y b b o o o
r r w g g g y b b o o o
r r r
y y y
y y y
Sample Output
0
1
1 1
链接
参考链接
ZOJ2477 IDA*搜索进阶 Author: HPUsDr
题目简述
还原魔方,求5步之内还原步数最少的方案之一。
方案表示:旋转面(如上图)+旋转方向(顺时针为1,逆时针为-1)。
如果不能再5步之内还原,则输出-1。
分析
估价函数:计算还有多少个小方格没有还原,向下取整(未还原个数/12)为最好情况下的剩下步数。每个面的中心位置的颜色不会发生改变。
模拟旋转,先对54个小方格进行标号
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 |
模拟每次旋转:
例如:旋转面为1时,
7 | 8 | 9 | ||
12 | 13 | 14 | 15 | 16 |
24 | 25 | 26 | 27 | 28 |
36 | 37 | 38 | 39 | 40 |
46 | 47 | 48 |
顺时针旋转一次时,7旋转到16,8旋转到28,9旋转到40……13旋转到15,14旋转到17……
共有3*4+8=20个方格的颜色发生了改变。
即把7位置赋值给16位置,a[16]=temp_a[7]。
{7,8,9,16,28,40,48,47,46,36,24,12/**/,13,14,15,27,39,38,37,25},②
{16,28,40,48,47,46,36,24,12,7,8,9/**/,15,27,39,38,37,25,13,14},③
顺时针旋转时,②地址上的值赋值给③上的地址;逆时针旋转时,③地址上的值赋值给②上的地址,
即 a[turn[k][j]]=temp_a[turn[k^1][j]];
k=2时,k^1==3;k=3时,k^1=2,(x为偶数时,x^1==x+1;x为奇数时,x^1==x-1)
程序分析
surface为6个面位置的标号,用于计算估价函数。
根据如下6个面,得到旋转数组turn,用于模拟魔方旋转。
旋转面为0:
1 | 4 | 7 | ||
21 | 10 | 11 | 12 | 13 |
33 | 22 | 23 | 24 | 25 |
45 | 34 | 35 | 36 | 37 |
52 | 49 | 46 |
旋转面为1:
7 | 8 | 9 | ||
12 | 13 | 14 | 15 | 16 |
24 | 25 | 26 | 27 | 28 |
36 | 37 | 38 | 39 | 40 |
46 | 47 | 48 |
旋转面为2:
9 | 6 | 3 | ||
15 | 16 | 17 | 18 | 19 |
27 | 28 | 29 | 30 | 31 |
39 | 40 | 41 | 42 | 43 |
48 | 51 | 54 |
旋转面为3:
3 | 2 | 1 | ||
18 | 19 | 20 | 21 | 10 |
30 | 31 | 32 | 33 | 22 |
42 | 43 | 44 | 45 | 34 |
54 | 53 | 52 |
旋转面为4:
21 | 20 | 19 | ||
10 | 1 | 2 | 3 | 18 |
11 | 4 | 5 | 6 | 17 |
12 | 7 | 8 | 9 | 16 |
13 | 14 | 15 |
旋转面为5:
37 | 38 | 39 | ||
36 | 46 | 47 | 48 | 40 |
35 | 49 | 50 | 51 | 41 |
34 | 52 | 53 | 54 | 42 |
45 | 44 | 43 |
get_h为估价函数。
程序
#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;
char a[100];
int surface[6][10]={
{1,2,3,4,5,6,7,8,9},
{10,11,12,22,23,24,34,35,36},
{13,14,15,25,26,27,37,38,39},
{16,17,18,28,29,30,40,41,42},
{19,20,21,31,32,33,43,44,45},
{46,47,48,49,50,51,52,53,54}
};
int circle[6]={5,23,26,29,32,50};
int turn[12][20]={
/**0**/
{1,4,7,13,25,37,46,49,52,45,33,21/**/,10,11,12,24,36,35,34,22},
{13,25,37,46,49,52,45,33,21,1,4,7/**/,12,24,36,35,34,22,10,11},
/**1**/
{7,8,9,16,28,40,48,47,46,36,24,12/**/,13,14,15,27,39,38,37,25},
{16,28,40,48,47,46,36,24,12,7,8,9/**/,15,27,39,38,37,25,13,14},
/**2**/
{9,6,3,19,31,43,54,51,48,39,27,15/**/,16,17,18,30,42,41,40,28},
{19,31,43,54,51,48,39,27,15,9,6,3/**/,18,30,42,41,40,28,16,17},
/**3**/
{3,2,1,10,22,34,52,53,54,42,30,18/**/,19,20,21,33,45,44,43,31},
{10,22,34,52,53,54,42,30,18,3,2,1/**/,21,33,45,44,43,31,19,20},
/**4**/
{21,20,19,18,17,16,15,14,13,12,11,10/**/,1,2,3,6,9,8,7,4},
{18,17,16,15,14,13,12,11,10,21,20,19/**/,3,6,9,8,7,4,1,2},
/**5**/
{37,38,39,40,41,42,43,44,45,34,35,36/**/,46,47,48,51,54,53,52,49},
{40,41,42,43,44,45,34,35,36,37,38,39/**/,48,51,54,53,52,49,46,47}
};
int get_h()
{
int ans=0;
for(int i=0;i<6;i++)
for(int j=0;j<9;j++)
if(a[surface[i][j]]!=a[circle[i]])
ans++;
return ans;
}
struct Ans
{
int surf;
int dir;
}ans[10],road[10];
int ans_cnt;
void dfs(int i)
{
int h=get_h();
if(i+ceil(h/12.0)>=6)
return;
if(ans_cnt!=-1&&i+ceil(h/12.0)>ans_cnt)
return;
if(h==0)//&&i<ans_cnt
{
if(ans_cnt==-1||i<ans_cnt)
{
for(int j=0;j<i;j++)
ans[j]=road[j];
ans_cnt=i;
}
return;
}
char temp_a[100];
memcpy(temp_a,a,sizeof(a));
for(int k=0;k<12;k++)
{
for(int j=0;j<20;j++)
a[turn[k][j]]=temp_a[turn[k^1][j]];
road[i].surf=k/2;
if(k%2==1)
road[i].dir=1;
else
road[i].dir=-1;
dfs(i+1);
memcpy(a,temp_a,sizeof(temp_a));
}
return;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
char x;
for(int i=1;i<=54;i++)
{
while(scanf("%c",&x)&&(x==' '||x=='\n'));
a[i]=x;
}
ans_cnt=-1;
dfs(0);
printf("%d\n",ans_cnt);
for(int i=0;i<ans_cnt;i++)
printf("%d %d\n",ans[i].surf,ans[i].dir);
}
return 0;
}
dfs的5步写成6步,然后6步转到的魔方答案不是-1,WA*10