这里对应的问题就是十六格拼图的问题,这里由于状态数较多,直接进行dfs或者bfs就无法在规定时间内求出解。这里就需要高等搜索算法了。

迭代加深

通过单纯的dfs无法在限定时间内找到初态到最终状态的最短路径,但是通过重复进行限制最大深度的DFS(深度受限搜索)却可以做到。简单地说就是在循环执行深度受限搜索的过程中逐步增加限制值limit,直到找到解为止。这种算法称为迭代加深。

PS:为了提高速度,迭代加深不会记录已经搜索过的状态。但是与此同时我们也需要做一些调整,防止出现回溯到上一状态的情况出现。

IDA*

在迭代加深中,通过推测值进行剪枝处理的算法成为IDA*或者A*。这里的推测值又称启发通常取可以完成目标所需的下限值

在十六格拼图中,如果能预估出当前状态到最终状态的最小成本h,我们就可以对搜索范围进行剪枝了。也就是说,如果当前深度g加上最小成本h(也就是在当前状态开始至少还需要h次状态迁移)超过了限制深度d,就可以直接中断搜索。

这里的h是一个预估值,不需要十分精确。并且,虽然增大h可以提高搜索速度,但是h太大的话可能会导致找不到解。

在十六宫格拼图问题中,我们以个拼图块到最终状态之间的曼哈顿距离总和为推测值h

A*

前面的是在迭代加深A*中使用推测值,实际上,推测值也可以用于含有优先级队列的狄克斯特拉算法(或广度优先搜索)为基础的算法,这类算法称为A*算法,它用优先级队列管理状态,优先对“起点到当前位置成本+当前位置到目标状态的推测值”最小的状态进行状态迁移,可以更快地找到解。

题目:ALDS1_13_C

下面是使用IDA*的解法

#include <bits/stdc++.h>
using namespace std;

#define N 4
#define N2 16

const int dx[] = {0, -1, 0, 1}; //分别对应上左下右移动
const int dy[] = {1, 0, -1, 0};
const string pth[] = {"u", "l", "d", "r"};

vector<int> path;
const int max_limit = 45;
int limit;

struct node
{
    int f[N2];
    int space, MD;
};

int MDT[N2][N2]; //u到v的曼哈顿距离

node current;
int get_all_MD(const node &nd)
{
    int ans = 0;
    for (int i = 0; i < N2; ++i)
    {
        if (nd.f[i] == N2)
            continue;
        ans += MDT[nd.f[i] - 1][i];
    }
    return ans;
}

bool dfs(int depth, int prev)
{
    if (current.MD == 0)
        return true;
    //当前深度加上启发,超过限制,则进行剪枝。
    if (depth + current.MD > limit)
        return false;

    int sx = current.space / N;
    int sy = current.space % N;

    node tmp;
    for (int i = 0; i < 4; ++i)
    {
        int tx = sx + dx[i];
        int ty = sy + dy[i];
        if (sx >= N || sx < 0 || sy >= N || sy < 0)
            continue;

        //防止回到上一状态
        if (abs(prev - i) == 2)
            continue;
        //暂存当前结果
        tmp = current;
        swap(current.f[current.space], current.f[tx * N + ty]);
        current.space = tx * N + ty;
        current.MD = get_all_MD(current);
        path.push_back(i);

        if (dfs(depth + 1, i))
            return true;
        path.pop_back();
        current = tmp;
    }
    return false;
}

int solve(node& in)
{
    in.MD = get_all_MD(in);
    //cout<<in.MD<<endl;

    for (limit = in.MD; limit <= max_limit; ++limit)
    {
        //cout << "limit:" << limit << endl;
        path.clear();
        if (dfs(0, -100))
        {
            return path.size();
        }
    }
    return -1;
}

int main()
{
    for (int i = 0; i < N2; ++i)
    {
        for (int j = 0; j < N2; ++j)
        {
            MDT[i][j] = abs(i / N - j / N) + abs(i % N - j % N);
        }
        cout << endl;
    }

    for (int i = 0; i < N2; ++i)
    {
        cin >> current.f[i];
        if (current.f[i] == 0)
        {
            current.space = i;
            current.f[i] = N2;
        }
    }
    printf("%d\n", solve(current));
    
}

转载请注明来源:https://www.longjin666.top/?p=1072

欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~

你也可能喜欢

发表评论