嘟嘟嘟​

IDA*


IDA*就是迭代加深的A*
最近想搞一搞迭代加深和A*算法。
挺简单的。
首先迭代加深是啥咧?首先在最朴素的搜索中,深度每次加\(1\),复杂度都会上升一个指数级,所以很有可能是第\(i\)层的复杂度比前\(i\)层的复杂度之和都大。因此,我们可以限制搜索深度,每一次在这个深度范围内搜索,然后搜索多次。如果当前深度得到了解,那么最优解就是当前深度,退出循环。这东西就叫迭代加深,迭代的是深度。
这样也可以看出来,迭代加深搜索最擅长的是求解步数比较少的搜索问题,即搜索树的深度小,分支较多的问题。
但是这样还是过不了这道题,还必须结合\(A*\)算法。
\(A*\)算法也不难理解,主要是对搜索的剪枝。想一下朴素的搜索中的剪枝:如果当前解比已知的最优解劣,就返回。然而这样优化并不能快多少。\(A*\)有一个更好的剪枝方法:如果当前解加上一个值比最优解劣,就返回。这个值是“估”出来的,就是当前状态离目标状态大约还有多少步,称作估价函数。
因此,当前步数加上估价值的结果一定要比答案劣,否则就可能会因为错误的剪枝而搜不到最优解。我是这么理解的:如果当前值加上一个十分优秀的值都比答案劣,那当前值肯定得舍去。


对于这道题,估价函数就是当前棋盘的状态和目标棋盘的状态有多少个格子不同。这一定比最优步数大,同时范围也是限制的最小。


代码及其好懂

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
//const int maxn = ;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}

const char f[5][5] = {{'1', '1', '1', '1', '1'},
{'0', '1', '1', '1', '1'},
{'0', '0', '*', '1', '1'},
{'0', '0', '0', '0', '1'},
{'0', '0', '0', '0', '0'}};
const int dx[] = {-2, -1, 1, 2, 2, 1, -1, -2};
const int dy[] = {1, 2, 2, 1, -1, -2, -2, -1};
char a[5][5];
int dep, sx, sy;

int h()
{
int ret = -1;
for(int i = 0; i < 5; ++i)
for(int j = 0; j < 5; ++j)
if(f[i][j] != a[i][j]) ret++;
return ret;
}
bool dfs(int stp, int x, int y)
{
if(stp > dep) return h() == -1 ? 1 : 0;
if(stp + h() > dep + 1) return 0; //A*剪枝
for(int i = 0; i < 8; ++i)
{
int newx = x + dx[i], newy = y + dy[i];
if(newx >= 0 && newx < 5 && newy >= 0 && newy < 5)
{
swap(a[x][y], a[newx][newy]);
if(dfs(stp + 1, newx, newy)) return 1;
swap(a[x][y], a[newx][newy]);
}
}
return 0;
}

int main()
{
int T = read();
while(T--)
{
for(int i = 0; i < 5; ++i) scanf("%s", a[i]);
for(int i = 0; i < 5; ++i)
for(int j = 0; j < 5; ++j)
if(a[i][j] == '*') {sx = i, sy = j; break;}
for(dep = 0; dep <= 15; ++dep) //迭代加深
if(dfs(1, sx, sy)) break;
write(dep > 15 ? -1 : dep), enter;
}
return 0;
}