The Rotation Game
Time Limit: 15000MS
|
|
Memory Limit: 150000K
|
Total Submissions: 944
|
|
Accepted: 218
|
Description
The rotation game uses a # shaped board, which can hold 24 pieces of square blocks (see Fig.1). The blocks are marked with symbols 1, 2 and 3, with exactly 8 pieces of each kind.
Initially, the blocks are placed on the board randomly. Your task is to move the blocks so that the eight blocks placed in the center square have the same symbol marked. There is only one type of valid move, which is to rotate one of the four lines, each consisting of seven blocks. That is, six blocks in the line are moved towards the head by one block and the head block is moved to the end of the line. The eight possible moves are marked with capital letters A to H. Figure 1 illustrates two consecutive moves, move A and move C from some initial configuration.
Input
The input consists of no more than 30 test cases. Each test case has only one line that contains 24 numbers, which are the symbols of the blocks in the initial configuration. The rows of blocks are listed from top to bottom. For each row the blocks are listed from left to right. The numbers are separated by spaces. For example, the first test case in the sample input corresponds to the initial configuration in Fig.1. There are no blank lines between cases. There is a line containing a single `0' after the last test case that ends the input.
Output
For each test case, you must output two lines. The first line contains all the moves needed to reach the final configuration. Each move is a letter, ranging from `A' to `H', and there should not be any spaces between the letters in the line. If no moves are needed, output `No moves needed' instead. In the second line, you must output the symbol of the blocks in the center square after these moves. If there are several possible solutions, you must output the one that uses the least number of moves. If there is still more than one possible solution, you must output the solution that is smallest in dictionary order for the letters of the moves. There is no need to output blank lines between cases.
Sample Input
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0
Sample Output
AC
2
DDHH
2
Source
Shanghai 2004
图中的#字格的4条竖线,可以按8个方向倒转里面的数字方块,当中间的8个数字方块是同一个数字时,游戏结束。这道题就要求搜索一个最短路径,倒转8个方向使得中间8个数字相等。这道题目看起来很像一道单纯的BFS,看了POJ里面说BFS会爆内存,我没试,估计写得好的也爆不了。但是估计写BFS还要涉及到状态的判重,程序写起来也不方便。我用了迭代加深的搜索方法。第一次接触这个算法,我说一下我的理解:
原来我很不理解迭代加深,搜索的深度一层一层地加,在后面的某一深度限制下搜索,必定会搜到前面深度所能搜到的结果,这会造成重复搜索。基于这点,我一直都认为迭代加深搜索的方法很冗余,当然也是自己从来都没有动手试过。像这道题就给我的收获不少,有的时候选择一定的策略进行搜索,我们是很难确定解所在状态空间的深度的,有时可能解的深度不大,但整个状态空间的深度很大,盲目的dfs搜索在状态空间里就有可能会越陷越深,迟迟出不了解,同时整个状态空间的宽度也很大,用BFS可能就会爆空间。迭代加深搜索恰恰是取了一个折中。利用了dfs的优势,限制了搜索的深度,避免了出现无解的境地。由于深度是逐个增加的,当搜到一个解后就退出,所以避免了BFS中判重的一步操作,当然在迭代深搜的过程中,还可以加入剪枝,可以优化程序。但是我的程序在POJ上还不快,还要找找原因,也许还有优化。下面是一些关键代码:
for(limit=0; ;limit++)
{
if(dfs(start,0))
{
if(limit == 0)
{
printf("No moves needed\n");
}
else
{
for(i=0; i<limit; i++)
{
printf("%c",'A'+pre[i]);
}
printf("\n");
}
printf("%d\n",rlt);
break;
}
}
///迭代过程
int dfs(struct S now, int depth)
{
int c1,c2,c3;
struct S st;
test(now,c1,c2,c3);
if(c1 == 8)
{
rlt=1;
return 1;
}
else if(c2 == 8)
{
rlt=2;
return 1;
}
else if(c3 == 8)
{
rlt=3;
return 1;
}
if(depth == limit)
return 0;
if(8-c1 > limit-depth && 8-c2 > limit-depth && 8-c3 > limit-depth)
return 0;
st=NewStateA(now);
pre[depth]=0;
if(dfs(st,depth+1))
return 1;
st=NewStateB(now);
pre[depth]=1;
if(dfs(st,depth+1))
return 1;
st=NewStateC(now);
pre[depth]=2;
if(dfs(st,depth+1))
return 1;
st=NewStateD(now);
pre[depth]=3;
if(dfs(st,depth+1))
return 1;
st=NewStateE(now);
pre[depth]=4;
if(dfs(st,depth+1))
return 1;
st=NewStateF(now);
pre[depth]=5;
if(dfs(st,depth+1))
return 1;
st=NewStateG(now);
pre[depth]=6;
if(dfs(st,depth+1))
return 1;
st=NewStateH(now);
pre[depth]=7;
if(dfs(st,depth+1))
return 1;
return 0;
}
///深搜
posted on 2008-04-20 15:44
飞飞 阅读(2688)
评论(1) 编辑 收藏 引用 所属分类:
ACM/ICPC