您的位置:首页 > 其它

POJ 2286 搜索 (IDA*)

2015-10-07 20:06 218 查看
题意:

旋转游戏在一个井字形的棋盘上进行,棋盘上有 24 块,每块都标着 1, 2, 3 中的一个,并且对于每个数字,恰好有 8 块标着它。

一开始,所有的块是随机码放在棋盘上的。你的任务即为移动这些块,使得包围着正中心空格的 8 块都标有同样的数字。

移动的方式只有一种,即为“旋转”井字形四列中的一列。所谓“旋转”就是指,将这一列中的所有块向两个方向之一移动一格,并将移出棋盘的那一块放置到这一列的最后。所以,共有 8 种旋转的方式,分别标为 A 到 H。

图(见poj原题中0.0)中标明了两步,从初始状态进行 A, C 两步移动即可满足要求。你的任务即为解决这一谜题。

这道题帮助我进一步理解了IDA*。不过是靠着刘汝佳叔叔的代码自己才A的这道题。而且还白痴地因为在不需要移动的情况时只输出了`No moves needed’ 而没输出中心的数字而W好多次。不是这个细节就可以1A..T^T

这个题就是搜到第一个有解的情况的那一种搜索,而我们控制搜索顺序使得搜到的第一个解为最优解(最短且字典序最小)。

不知道为什么我的代码跑的比刘汝佳叔叔的快而且内存还小,我为了省事,使用了很不提倡的做法:函数传递数组+每层递归里新开一个数组。保险一点的做法还是像刘汝佳叔叔一样再写一个rerotate数组。

h函数使用的比较“保守”,最多只能估测不到8层——在我们不知道最长的答案是多少的情况下。一开始我开的1005,之后又换成105交了一次仍然可以,再换成25还是可以(逗X在自娱自乐)。这么看来,这个h函数性能还是很好的。就是h() = min(dif(1), dif(2), dif(3))。dif(i)表示中心8个数字中与i不同的数字。含义就是,当前中心8个数字中最多的是i,有k个,假设我们每旋转一次就使得k++,h()返回还需要旋转的次数。很显然,真实情况是不会小于h()返回的这个值的,所以正确性得证。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

char ans[1005];
int pos, maxd, beg[24];
int center[9] = {0, 6, 7, 8, 11, 12, 15, 16, 17};
int r[8][24] = {
{2, 1, 6, 3, 4, 5, 11, 7, 8, 9, 10, 15, 12, 13, 14, 20, 16, 17, 18, 19, 22, 21, 0, 23},
{0, 3, 2, 8, 4, 5, 6, 7, 12, 9, 10, 11, 17, 13, 14, 15, 16, 21, 18, 19, 20, 23, 22, 1},
{0, 1, 2, 3, 10, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 19, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23},
{0, 23, 2, 1, 4, 5, 6, 7, 3, 9, 10, 11, 8, 13, 14, 15, 16, 12, 18, 19, 20, 17, 22, 21},
{22, 1, 0, 3, 4, 5, 2, 7, 8, 9, 10, 6, 12, 13, 14, 11, 16, 17, 18, 19, 15, 21, 20, 23},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 13, 20, 21, 22, 23},
{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 4, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
};

int h(int *n){
int res = 8;
for(int end = 1; end <= 3; end++){
int t = 0;
for(int i = 1; i <= 8; i++){
t += end != n[center[i]];
}
res = min(res, t);
}
return res;
}

bool ok(int *n){
pos = n[center[1]];
for(int i = 1; i <= 8; i++){
if(n[center[i]] != pos) return 0;
}
return 1;
}

bool dfs(int *n, int ed){
if(ed + h(n) > maxd) return 0;
if(ok(n)){
ans[ed] = '\0';
printf("%s\n", ans);
return 1;
}
for(int i = 0; i < 8; i++){
ans[ed] = 'A' + i;
int k[24];
for(int j = 0; j < 24; j++){
k[j] = n[r[i][j]];
}
if(dfs(k, ed+1)) return 1;
}
return 0;
}

int main()
{
while(scanf("%d", beg) && beg[0]){
for(int i = 1; i < 24; i++){
scanf("%d", beg + i);
}
if(ok(beg)){
puts("No moves needed");
printf("%d\n", pos);
continue;
}
for(maxd = 1; ; maxd++){
if(dfs(beg, 0)){
printf("%d\n", pos); break;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 搜索