迭代加深搜索(IDDFS)和启发式迭代加深搜索(IDA*))

假设现在有一个任务,这个任务要通过深度优先搜索(DFS)完成,并且搜索深度可能很深,比如 20 20 20 层。但是答案一般在 5 5 5 层。

怎么设计搜索可以尽快完成任务?

DFS

深度优先搜索(DFS),通过递归实现。通过从一个状态扩散出很多个状态,一直搜索直到搜索结束条件满足。通常可以解决很多问题。深度优先搜索广泛应用于各种问题。但是深度优先搜索的效率是个问题。

对于上面情景的问题,搜索可能从一个分支搜索了很久,然后发现在另一个分支搜了三次就搜到了。

IDDFS

这个时候可以用迭代加深搜索进行 DFS。

迭代加深搜索(IDDFS)本质是 DFS,是通过枚举搜索最大层数,如果讲最大层数设置为 x x x 可以有答案是就可以输出答案,否则,将 x x x 加上 1 1 1 后继续搜索。这样可以有效规避答案层数很浅的情况,但是会稍微耗时一点。

如果答案通常在很浅的地方,IDDFS 会发挥很大的作用。

伪代码实现

IDDFS(初始状态,最大层数, 层数):
	如果 层数 == 最大层数:
		返回 -1
	从 初始状态 扩散出状态为 下一个状态:
		下一状态答案 为 IDDFS(下一个状态, 最大层数, 层数 + 1) 
		如果 下一状态答案 不为 -1:
			返回 下一状态答案
	返回 -1
			
获取答案:
	让 x 从 1 到 100 循环:
		当前答案 = IDDFS(初始状态, x, 0)
		如果 当前答案 不为 -1:
			返回 当前答案

IDA*

IDA* 是一个在 IDDFS 中加上了估价函数的搜索方式。总体原理和 IDDFS 相似,但是在实现是会加上一个估价函数以剪枝。估价函数是用来判断这个状态可不可能到达终点的。

伪代码实现

IDDFS(初始状态,最大层数, 层数):
	如果 层数 == 最大层数:
		返回 -1
	如果 估价(初始状态, 层数) 为假:
		返回 -1
	从 初始状态 扩散出状态为 下一个状态:
		下一状态答案 为 IDDFS(下一个状态, 最大层数, 层数 + 1) 
		如果 下一状态答案 不为 -1:
			返回 下一状态答案
	返回 -1
			
获取答案:
	让 x 从 1 到 100 循环:
		当前答案 = IDDFS(初始状态, x, 0)
		如果 当前答案 不为 -1:
			返回 当前答案

例题

洛谷P2324 骑士精神

此题使用 IDA* 实现。先枚举最大步数,如果当前步数可以得到答案,输出这个步数。

检查答案函数内部,就是 IDA*。估价函数的设计,每 k k k 次移动,最多让答案和当前状态减少 k − 1 k - 1 k1 处。如果我们还可以移动的次数在答案状态和当前状态不同处的个数外,就不可以实现,返回 0 0 0。这样可以让计算量大大的减少。

AC Code:

#include <bits/stdc++.h>
using namespace std;
int T;
char s[10][10];
char t[10][10] = {
	"",
	" 11111",
	" 01111",
	" 00*11",
	" 00001",
	" 00000"
};
int cnt() {
	int ret = 0;
	for (int i = 1; i <= 5; i++) {
		for (int j = 1; j <= 5; j++) {
			if (t[i][j] != s[i][j])
				ret++;
		}
	}
	return ret;
}
int dx[10] = {-2, -2, -1, -1, 1, 1, 2, 2};
int dy[10] = {-1, 1, -2, 2, -2, 2, -1, 1};
int x, y;
int c;
bool dfs(int dep, int mdep, int x, int y) {
	c = cnt();
	if (dep == mdep) {
		if (!c)
			return 1;
		return 0;
	}
	if (c + dep - 1 > mdep)
		return 0;
	for (int i = 0; i < 8; i++) {
		int nx = x + dx[i], ny = y + dy[i];
		if (nx >= 1 && nx <= 5 && ny >= 1 && ny <= 5) {
			swap(s[x][y], s[nx][ny]);
			if (dfs(dep + 1, mdep, nx, ny)) {
				return 1;
			}
			swap(s[x][y], s[nx][ny]);
		}
	}
	return 0;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--) {
		for (int i = 1; i <= 5; i++) {
			for (int j = 1; j <= 5; j++) {
				cin >> s[i][j];
				if (s[i][j] == '*') {
					x = i, y = j;
				}
			}
		}
		bool flag = 0;
		for (int i = 0; i <= 15; i++) {
			if (dfs(0, i, x, y)) {
				cout << i << '\n';
				flag = 1;
				break;
			}
		}
		if (!flag) {
			cout << "-1\n";
		}
	}
	return 0;
}
  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值