The Rotation Game (POJ 2286) 题解

【问题描述】

(由于是英文的,看不懂,这里就把大意给大家说一下吧……都是中国人,相信大家也不愿意看英文……)

如图,一个井字形的棋盘,中间有着1-3任意的数,有ABCDEFGH八个操作,每个操作意味着该操作所在行朝该操作方向整体移动一格,详见图,你的目的是:对于输入的多组数据,用最少的步数使得井字形棋盘中间的八个数为同一个数,若不需操作就已达到要求,则输出“No moves needed”,无论是否需要操作,你都应将中间的数字给输出。输入以一个0结束。

【样例输入】

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

【样例输出】

AC

2

DDHH

2

【解题思路】

又是一道求最少步数的题目……果断写广搜,然而,写完广搜后,我奇迹般地发现……MLE了…………………………空间只给了150MB,我再一看时间………………15000ms……也不想多说什么了,赶紧用上今天刚学的IDA*算法。

IDA*算法是一种将估价函数与深搜结合的搜索方法,搜索方式是用深度优先搜索的方式,搜完第k层若还没有结果,那么就退出,然后从第一层开始搜到第k+1层,不断加深所搜的层数,因此又叫迭代加深搜索。其实说这么复杂,按我的理解,就是用深搜来做的广搜……

现在我们来看一下题目。因为是井字型棋盘,且输入还是一行数,那么,我们就给棋盘上的数标上号,分别为1-24,那么八个移动的过程也可以表示出来了,然后由于是深搜,那么就还有回溯的过程,对于每一个操作,都需要一个反操作,而题目中正好又提示了我们,A的反操作是F等等,因此,我们只需要记录每个操作的反操作是第几个就行了。

然后是边界条件,这里的边界条件是当搜索层数大于当前所设置的最大深度限制时,便退出,实际上每一个迭代加深搜索都有这个边界条件,而另外的边界条件则因题目而异,这道题则不需要其他的边界条件,满足要求退出即可。

接下来考虑初始化的问题,我们在找中间的值的时候,自然是要找最多的数,然后将其他的数移成这个数就行了,那么估价函数就是8-最大的数的个数,从这个估价函数的层数开始搜索,详见代码。

【代码实现】

 1 const xh:array[1..8,1..7] of longint=((1,3,7,12,16,21,23),(2,4,9,13,18,22,24),(11,10,9,8,7,6,5),(20,19,18,17,16,15,14),(24,22,18,13,9,4,2),(23,21,16,12,7,3,1),(14,15,16,17,18,19,20),(5,6,7,8,9,10,11));
 2       fan:array[1..8] of longint=(6,5,8,7,2,1,4,3);
 3       op:array[1..8] of char=(‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘,‘G‘,‘H‘);
 4       mid:array[1..8] of longint=(7,8,9,12,13,16,17,18);
 5 var n,m,dep:longint;
 6     s:array[1..24] of longint;
 7     a:array[1..50] of longint;
 8     i,j:longint;
 9 function max(a,b,c:longint):longint;
10 begin
11  max:=a;
12  if b>max then
13   max:=b;
14  if c>max then
15   max:=c;
16 end;
17 function get:longint;
18 var i:longint;
19     cnt:array[1..4] of longint;
20 begin
21  fillchar(cnt,sizeof(cnt),0);
22  for i:=1 to 8 do
23   inc(cnt[s[mid[i]]]);
24  exit(8-max(cnt[1],cnt[2],cnt[3]));
25 end;
26 procedure move(k:longint);
27 var i,t:longint;
28 begin
29  t:=s[xh[k,1]];
30  for i:=1 to 6 do
31   s[xh[k,i]]:=s[xh[k,i+1]];
32  s[xh[k,7]]:=t;
33 end;
34 function dfs(k:longint):boolean;
35 var i,h:longint;
36 begin
37  if k>=dep then
38   exit(false);
39  for i:=1 to 8 do
40   begin
41    move(i);//移动
42    a[k]:=i;
43    h:=get;//求最多的数的个数
44    if h=0 then exit(true);
45    if (k+h<dep)and(dfs(k+1)) then//深搜
46     exit(true);
47    move(fan[i]);//回溯
48   end;
49  exit(false);
50 end;
51 begin
52  read(s[1]);
53  while s[1]<>0 do
54   begin
55    for i:=2 to 24 do
56     read(s[i]);
57    dep:=get;
58    if dep=0 then
59     begin
60      writeln(‘No moves needed‘);//所给数据本就满足要求,输出,退出
61      writeln(s[7]);
62      read(s[1]);
63      continue;
64     end;
65    while not(dfs(1)) do//如果不满足要求,加深层数,再进行深搜
66     inc(dep);
67    for i:=1 to dep-1 do
68     write(op[a[i]]);
69    writeln;
70    writeln(s[7]);
71    read(s[1]);
72   end;
73 end.
时间: 2024-10-06 12:15:16

The Rotation Game (POJ 2286) 题解的相关文章

POJ 2286 The Rotation Game 迭代搜索深度 + A* == IDA*

感觉这种算法还是比较局限的吧,重复搜索是一个不好的地方,而且需要高效的估值函数来进行强剪枝,这点比较困难. 迭代搜索深度是一个比较炫酷的搜索方式,不过有点拿时间换空间的感觉. 首先迭代深度比较搓的写法是,首先设置一个阀值MaxH,初始为最小值. 当在搜索深度Depth <= MaxH时找到解则此时为最优解,否则MaxH++,继续深搜. 另外一种比较吊的写法是二分搜索深度,若搜到则减小阀值,否则增大阀值. 总之,迭代深度搜索就是通过改变深搜的深度来寻找最优解,这样做的好处是省掉了BFS中状态标记所

POJ 2286 The Rotation Game(IDA*)

The Rotation Game Time Limit: 15000MS   Memory Limit: 150000K Total Submissions: 6396   Accepted: 2153 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

【POJ 2286】 The Rotation Game

[题目链接] http://poj.org/problem?id=2286 [算法] IDA* [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #inclu

(IDA*)POJ 2286 The Rotation Game

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

POJ - 2286 - The Rotation Game (IDA*)

IDA*算法,即迭代加深的A*算法,实际上就是迭代加深+DFS+估价函数 题目传送:The Rotation Game AC代码: #include <map> #include <set> #include <list> #include <cmath> #include <deque> #include <queue> #include <stack> #include <bitset> #include

The Rotation Game (poj 2286 搜索IDA*)

Language: Default The Rotation Game Time Limit: 15000MS   Memory Limit: 150000K Total Submissions: 5573   Accepted: 1878 Description The rotation game uses a # shaped board, which can hold 24 pieces of square blocks (see Fig.1). The blocks are marked

poj - 3641 题解

题意:检验一个数是否是质数,且满足ap = a (mod p) 题解:快速幂,质数检验 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 long long power(long long a,long long b,long long c) 7 { 8 long long res,t; 9 res=

poj - 3070 题解

题意:斐波那契数列的矩阵链乘求法. 题解:快速幂优化矩阵链乘解决. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 struct datatype 7 { 8 int a[2][2]; 9 }; 10 datatype multiple(datatype x,datatype y) 11 { 1

poj 1066 题解

题意:求从正方体外面到达这个黑点所需穿过的最少线段数(规定只能从线段中点穿过,包括最外层的墙),共有n面墙 0 <= n <= 30 题解:事实上枚举边界上的中点,判断它和黑点的线段与这些墙的交点数即可 解释:注意到,墙这一长线段相对于黑点连线,等价于直线--无论是在实现上还是题意上.连线若与墙相交,则黑点与枚举点必在墙两侧,无可避免地要穿过这面墙,至于从线段中点穿过在本题中是没有意义的.起始点选取本该在线段中点,但显然选取两个端点的最小值不会比它差,而一个端点的结果不会比相邻的两个中点结果好