一,算法思路(参考这里)
迭代加深算法:
总体上按照深度优先方法进行,对搜索深度需要给出一个限制dm,当深度达到了dm的时候,如果还没有找到解答,就停止对改分支的搜索。dm从1开始,从小到大一次增大(因此称为迭代加深)。迭代加深搜索是最优的也是完备的。
IDA*算法:迭代加深的A*算法
其实就是将A*和迭代加深算法结合起来。
优先将初始状态结点的估价函数H值设置为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;如果没有找到解,则加大阈值maxH,再重复上述搜索,直到找到一个解。在保证H值的计算满足A*算法的要求(相容,递增)下,可以证明找到的这个解一定是最优解。
在程序实现上,IDA*要比A*方便,因为不需要保存结点,不需要判重复,也不需要对根据H值对结点排序,占用空间小。但是IDA*对一个结点可能多次搜索到。
在一般的问题中,是这样使用IDA*的,当前局面的估价函数值+当前的搜索深度>预定义的最大搜索深度时,就停止继续往下搜索。
伪代码如下(参考这里):
node current node
g the cost to reach current node
f estimated cost of the cheapest path (root..node..goal)
h(node) estimated cost of the cheapest path (node..goal)
cost(node, succ) path cost function
is_goal(node) goal test
successors(node) node expanding function
procedure ida_star(root)
bound := h(root)//起始深度限制是起点的H值
loop
t := search(root, 0, bound)
if t = FOUND then return FOUND
if t = ∞ then return NOT_FOUND
bound := t//如果没有搜到就加大限制,返回的t是本次搜索中超过上次限制的最小f值
end loop
end procedure
function search(node, g, bound)
f := g + h(node)
if f > bound then return f
if is_goal(node) then return FOUND
min := ∞
for succ in successors(node) do
t := search(succ, g + cost(node, succ), bound)
if t = FOUND then return FOUND
if t < min then min := t
end for
return min
end function
poj 2286的题意:
在如下图的棋盘中,摆放着8个1,8个2和8个3,每一步你可以沿着A、B、C、D、E、F、G、H任意一个方向移动该字母所指的长块。移出边界的小块会从另一端移进来。如图,最左边的棋盘经过操作A,就会变成中间的棋盘布局,再进行操作C,就会变成右边的棋盘布局。
你需要设法使的最中间的8个格子的数字相同,问最少需要多少步。如何移动?
可以使用IDA*算法来求解。
代码如下:
/*************************************************************************
> File Name: 2286.cpp
> Author: gwq
> Mail: gwq5210@qq.com
> Created Time: 2015年08月31日 星期一 16时01分00秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef pair<int, int> pii;
typedef long long ll;
const double esp = 1e-5;
#define N 30
int num[N], bound;
char ans[N * N];
int center[] = {7, 8, 9, 12, 13, 16, 17, 18};
int r[] = {5, 4, 7, 6, 1, 0, 3, 2};
int mp[][8] = {
{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},
};
int geth(int num[])
{
int ret = 0;
int cnt[4] = {0, 0, 0, 0};
for (int i = 0; i < 8; ++i) {
cnt[num[center[i]]]++;
}
ret = max(cnt[1], ret);
ret = max(cnt[2], ret);
ret = max(cnt[3], ret);
return 8 - ret;
}
void move(int op)
{
const int *arr = mp[op];
int t = num[arr[0]];
for (int i = 1; i < 7; ++i) {
num[arr[i - 1]] = num[arr[i]];
}
num[arr[6]] = t;
}
int dfs(int cur)
{
if (cur > bound) {
return 0;
}
if (!geth(num)) {
return 1;
}
for (int i = 0; i < 8; ++i) {
ans[cur] = 'A' + i;
move(i);
int h = geth(num);
if (h + cur <= bound) {
if (dfs(cur + 1)) {
return true;
}
}
move(r[i]);
}
return false;
}
int main(int argc, char *argv[])
{
scanf("%d", &num[1]);
while (num[1] != 0) {
for (int i = 2; i <= 24; ++i) {
scanf("%d", &num[i]);
}
bound = geth(num);
if (!bound) {
printf("No moves needed\n");
} else {
while (!dfs(0)) {
bound++;
}
ans[bound] = '\0';
printf("%s\n", ans);
}
printf("%d\n", num[center[0]]);
scanf("%d", &num[1]);
}
return 0;
}