双向BFS (广搜) \(O(8 ^ 7)\)


看到没有双向BFS的题解我就过来了

这道题也可以用双向\(BFS\)来做,时间复杂度与\(IDA*\)不相上下。

双向\(BFS\)的实现有多种:

  1. 把初始状态和目标状态扔在一个队列里,每次从队列里搞出来一个扩展
  2. 把初始状态和目标状态扔在两个队列里,每次选一个队列中元素少的拓展。
  3. 把初始状态和目标状态扔在两个队列里,每次分别从两个队列中取出一个元素拓展。

这里使用了方法\(1\)。


时间复杂度分析:每次会扩展\(8\)个状态,最多扩展\(\lfloor\frac{15}{2}\rfloor = 7\)次(到第八次如果还找不到则肯定超过限制的\(15\)步,答案则无需扩展),所以复杂度是\(O(8 ^ 7)\)的

具体实现方面看代码。

C++ 代码

#include <iostream>
#include <cstdio>
#include <unordered_map>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[8] = {-2, 2, 2, -2, 1, -1, 1, -1};
//移动方向的打表
int n;
//状态结构体
struct Node{
int v[5][5], f, x, y;
//f = 0 表示从初始状态出发, f = 1 表示从目标状态出发
}s, t, u;
unordered_map<int, int> step[2][30];
// 记录每个状态对应的位置。
int goal[5][5] = {
{1, 1, 1, 1, 1},
{0, 1, 1, 1, 1},
{0, 0, 2, 1, 1},
{0, 0, 0, 0, 1},
{0, 0, 0, 0, 0}
};
//目标状态打表
int start[5][5]; //get(x) 获取状态x的步数
int get(Node x){
int sum = 0;
//把一个位置状态转移成一个二进制数,比较方便。
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
if(x.v[i][j] == 1)
sum |= 1 << (i * 5 + j);
if(step[x.f][x.x * 5 + x.y].count(sum) == 0) return INF;
return step[x.f][x.x * 5 + x.y][sum];
}
//set() 设置状态x的步数
void set(Node x, int val){
int sum = 0;
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
if(x.v[i][j] == 1)
sum |= 1 << (i * 5 + j);
step[x.f][x.x * 5 + x.y][sum] = val;
}
int bfs(){
queue<Node> q;
q.push(s); q.push(t);
set(s, 0);
set(t, 0);
while(!q.empty()){
Node u = q.front(); q.pop(); //找到同位置的另一状态
Node l = u; l.f = u.f ^ 1; //如果相遇,代表已经找到一条最短的路径
if(get(u) + get(l) <= 15)
return get(u) + get(l); //说明所有状态已经都至少走了 8 步, > 最大限制 15
if(get(u) >= 8) break; l.f = u.f;
for(int i = 0; i < 8; i++){
int nx = u.x + dx[i], ny = u.y + dy[i];
if(nx < 0 || nx >= 5 || ny < 0 || ny >= 5) continue;
swap(l.v[u.x][u.y], l.v[nx][ny]);
l.x = nx, l.y = ny; if(get(u) + 1 < get(l)){
set(l, get(u) + 1);
q.push(l);
}
//还原现场
swap(l.v[u.x][u.y], l.v[nx][ny]);
}
}
return -1;
}
int main(){
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
t.v[i][j] = goal[i][j];
t.f = 1; t.x = 2; t.y = 2;
int T; scanf("%d", &T);
while(T--){
for(int i = 0; i < 2; i++)
for(int j = 0; j < 30; j++)
step[i][j].clear();
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
char x; cin >> x;
if(x == '*')s.x = i, s.y = j, s.v[i][j] = 2;
else s.v[i][j] = x - '0';
}
}
s.f = 0;
printf("%d\n", bfs());
}
return 0;
}

AcWing 195. 骑士精神的更多相关文章

  1. BZOJ1085: [SCOI2005]骑士精神 [迭代加深搜索 IDA*]

    1085: [SCOI2005]骑士精神 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1800  Solved: 984[Submit][Statu ...

  2. A*算法详解 BZOJ 1085骑士精神

    转载1:A*算法入门 http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx 在看下面这篇文章之前,先介绍几个理论知识,有助于理解A*算 ...

  3. 【BZOJ】1085: [SCOI2005]骑士精神(A*启发式搜索)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1085 囧啊囧,看了题解后写了个程序,但是样例总过不了T+T,调试了不下于1个小时,肉眼对拍看了根本看 ...

  4. 【bzoj1085】[SCOI2005]骑士精神

    1085: [SCOI2005]骑士精神 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1757  Solved: 961[Submit][Statu ...

  5. 【BZOJ 1085】 [SCOI2005]骑士精神

    Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2, ...

  6. Codevs 2449 骑士精神 2005年省队选拔赛四川

    2449 骑士精神 2005年省队选拔赛四川 时间限制: 1 s 空间限制: 128000 KB 题目等级 : **大师 Master** 题目描述 Description 在一个5×5的棋盘上有12 ...

  7. BZOJ 1085: [SCOI2005]骑士精神( IDDFS + A* )

    一开始写了个 BFS 然后就 T 了... 这道题是迭代加深搜索 + A* -------------------------------------------------------------- ...

  8. [bzoj1805][SCOI2005]骑士精神 [启发式搜索]

    Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2, ...

  9. 【日常学习】【IDA*】codevs2449 骑士精神题解

    题目描写叙述 Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位.在不论什么时候一个骑士都能依照骑士的走法(它能够走到和它横坐标相差为1.纵坐标相差为2或 ...

随机推荐

  1. 【java从入门到精通】day-07-逻辑运算符-位运算符-条件运算符-扩展赋值运算符

    逻辑与(&&).或(||).非(!) 示例: package operator;​public class Demo05 {    public static void main(St ...

  2. ArrayList和LinkedList 的联系和区别

    ArrayList和LinkedList 的联系和区别 1.联系: 都实现了List接口 有序 不唯一(可重复) 2.区别 ArrayList LinkedList

  3. 应用程序-特定 权限设置并未向在应用程序容器不可用 SID (不可用)中运行的地址 LocalHost (使用 LRPC) 中的用户...的 COM 服务器应用程序的 本地 激活 权限。此安全权限可以使用组件服务管理工具进行修改。

    很久以前发现我们的业务服务器上出现一个System的系统严重错误,查找很久都没有找到解决办法,今日再次查看服务器发现报错更频繁,于是就搜集各种资料进行查找解决办法,终于找到了一个解决办法. 错误截图介 ...

  4. 面试腾讯,字节跳动首先要掌握的Java多线程,一次帮你全掌握!

    一.程序,进程,线程联系和区别 其实程序是一段静态的代码,它是应用程序执行的脚本.进程就是程序动态的执行过程,它具有动态性,并发性,独立性.线程是进程调度和执行的单位. 进程:每个进程都有独立的代码和 ...

  5. Talk About My Route To Edit

    Initially, I plan to write 4 columns:Python, Qt, Linux,and respectively, Career. However, my ambitio ...

  6. 怎么在苹果笔记本上用Folx重新下载已完成的任务

    大家在完成了任务下载后,有时会将下载的文件移动到其他文件夹中,或者是,当下载的文件已经使用完毕时,有些用户会将文件删除.以上的两种情况,都会导致Folx所属任务查看功能失效,也就是说,无法找到任务对应 ...

  7. EasyRecovery帮您轻松拯救办公室断电后的文件丢失

    故事要从半个月前说起,某天中午,社畜小编得到了上头的传令,要为即将到来的双十一狂欢节写一个活动策划案. 想着时间也不是很充裕,还要留一些时间修修补补,于是小编连续三天挑灯夜战,终于在某天周五的晚上把策 ...

  8. CorelDRAW 2017提示已安装另一版本导致安装失败的解决办法

    Coreldraw提示"由于您已安装了另一版本,因此无法安装本产品.要安装本产品,您必须首先卸载现有版本"的情况在Coreldraw X8及Coreldraw 2017上都存在,下 ...

  9. 【ES6】ES6入门笔记

    1.概要 - ECMAScript2015(ES6)是Javascript最标准的语法式样,是在2015年6月由Ecma国籍组织公布的最新版本,现在已经被多个领域和浏览器所广泛采纳和使用. 2.学习网 ...

  10. Spring简介以及配置信息

      Spring框架是一种轻量级的.一站式的企业级开发解决方案 框架(framework):是一组设计思想.规范.API的精心组合,专门用来解决某一层次或领域的问题 轻量级(lightweight): ...