卸载前面
搜索很重要 尤其是爆搜
迭代加深搜索
原理
本来一波搜索搜到底,但是可能搜到底都不带有答案的
我们现在规定一个答案的深度k
如果达到k仍然没有结果,返回
深度+1, 重复上述, 直到一个k能搜到答案
显然复杂度降低了
例题
我就光会棋盘上跳来跳去的那种
P2324 骑士精神
我们规定答案在k出现,你跳k步都找不到答案就说明答案在k+1到更深
code
P1379 八数码难题
我们规定答案在k出现,你跳k步都找不到答案就说明答案在k+1到更深
总结
就当你发现一下子搜到底也搜不出啥来的时候就可以往迭代加深想
启发式搜索
原理
我不太懂怎么出现这个名字的
好像就是dfs中
借助一个估价函数来判断
当前状态和已求出的答案哪个更优
就比如说 当前用最好的方法走下去 还比已求的步数多
就直接不求了
刷的题有点少 感觉好像就是一个剪枝换了个牛逼的名字?
例题
P2324 骑士精神
和目标棋盘不一样的 + 已经走了的 > 你要的k 就不搜了
code
P1379 八数码难题
和目标棋盘不一样的 + 已经走了的 > 你要的k 就不搜了
总结
就一个剪枝吧 可以这么说么
而且上边两个题 通过棋盘比较来估算
也不是说哪个棋盘搜起来这样子都对
因为有的题目我就没看见有用这种方法剪枝的
所以说启发式搜索需要启发的思维 服了
双向bfs
原理
知道一个东西的开始和结束的样子就可以
从开始bfs,从结束bfs
中间相遇了,说明相遇了
为什么用两头搜呢
一个是从开头搜空间指数增长 两头搜降空间
还有就是复杂度指数增长
一般本来 (O(2^n)) 的两头搜能降到(O(2^{frac{n}{2}}))
而且怎么说呢 开两个队列搜还不很难写
所以就有一点迭代加深的意思了
怎么说呢 比如
int cnt = 0;
while(1) {
cnt ++;
if(q[1].size() < q[0].size()) bfs(1);
else bfs(0);
if(flag == 1) cout<<cnt - 1, break;
}
大概这个意思
例题
P2324 骑士精神
知道开始结束 直接双向就行
code
P1379 八数码难题
知道开始结束 直接双向就行
openjudge哆啦A梦的时光机
知道开始结束 直接双向就行
code
P2578 九数码游戏
直接开八维数组判重也行hash也行
反正知道开始结束 直接双向就行
总结
知道开始结束直接双向就行
开两个队列 两头走
按size小的先扩展
总结
八数码难题和骑士精神是两个好题 咋都能做
所以说要做的烂烂的
棋盘上的不一定就带bfs dfs也行
而且没有依据应该是dfs还是bfs
靠感觉写