poj 2286 The Rotation Game IDA*算法

一,算法思路(参考这里)
迭代加深算法:
总体上按照深度优先方法进行,对搜索深度需要给出一个限制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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值