但是我们还不是很清楚每一次的状态怎么储存?我们可以用一个结构体,将每次的位置存起来,但是这个程序中用了一个更好的储存方法:我们知道最大的格数是16*16个,也就是256个,那么我们转换为二进制表示就是8位数,那么我们可以使用24位的二进制表示啊!然后我们再进行解压缩,所以这就是很神奇的地方!

普通BFS

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
//const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std; const int maxn = ;
const int maxs = ;
const int dx[] = { ,-,,, };
const int dy[] = { ,,,-, }; inline int ID(int a, int b, int c) {
return (a << ) | (b << ) | c;
} int s[], t[]; int deg[maxn]; //记录每个编号为i的空格周围可以走的步数
int G[maxn][]; inline bool conflict(int a, int b, int a2, int b2) {
return a2 == b2 || (a2 == b && b2 == a);
} int d[maxn][maxn][maxn]; int bfs() {
queue<int> q;
memset(d, -, sizeof d);
q.push(ID(s[], s[], s[]));
d[s[]][s[]][s[]] = ;
while (!q.empty()) {
int u = q.front();
q.pop();
int a = (u >> ) & 0xff, b = (u >> ) & 0xff, c = u & 0xff; //解码出三个鬼的位置
if (a == t[] && b == t[] && c == t[]) return d[a][b][c];
for (int i = ; i < deg[a]; i++) {
int a2 = G[a][i];
for (int j = ; j < deg[b]; j++) {
int b2 = G[b][j];
if (conflict(a, b, a2, b2)) continue;
for (int k = ; k < deg[c]; k++) {
int c2 = G[c][k];
if (conflict(a, c, a2, c2)) continue;
if (conflict(b, c, b2, c2)) continue;
if (d[a2][b2][c2] != -) continue;
d[a2][b2][c2] = d[a][b][c] + ;
q.push(ID(a2, b2, c2));
}
}
}
}
return -;
} int main() {
int w, h, n; while (scanf("%d%d%d", &w, &h, &n) == && n) {
char maze[][];
for (int i = ; i < h; i++) fgets(maze[i], , stdin); int cnt, x[maxn], y[maxn], id[maxs][maxs];
cnt = ;
for (int i = ; i < h; i++) {
for(int j=;j<w;j++)
if (maze[i][j] != '#') {
x[cnt] = i;
y[cnt] = j;
id[i][j] = cnt;
if (islower(maze[i][j])) s[maze[i][j] - 'a'] = cnt;
else if (isupper(maze[i][j])) t[maze[i][j] - 'A'] = cnt;
cnt++;
}
} for (int i = ; i < cnt; i++) {
deg[i] = ;
for (int dir = ; dir < ; dir++) {
int xx = x[i] + dx[dir], yy = y[i] + dy[dir];
if (maze[xx][yy] != '#') G[i][deg[i]++] = id[xx][yy];
}
} if (n <= ) {
deg[cnt] = ;
G[cnt][] = cnt;
s[] = t[] = cnt++;
}
if (n <= ) {
deg[cnt] = ;
G[cnt][] = cnt;
s[] = t[] = cnt++;
} printf("%d\n", bfs()); }
return ;
}

双向BFS

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
//const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std; const int maxn = ;
const int maxs = ;
const int dx[] = { ,-,,, };
const int dy[] = { ,,,-, }; inline int ID(int a, int b, int c) {
return (a << ) | (b << ) | c;
} int s[], t[]; int deg[maxn]; //记录每个编号为i的空格周围可以走的步数
int G[maxn][];
char maze[maxn][maxn];
int color[maxn][maxn][maxn]; inline bool conflict(int a, int b, int a2, int b2) {
//两个鬼是exchange位置(违反第2条)
//两个鬼移动到同一个格子(违反第1条)
return a2 == b2 || (a2 == b && b2 == a);
} int d1[maxn][maxn][maxn]; int bfs() {
queue<int> qf;
queue<int> qb; d1[s[]][s[]][s[]] = ;
d1[t[]][t[]][t[]] = ; qf.push(ID(s[], s[], s[]));
qb.push(ID(t[], t[], t[])); while (!qf.empty() || !qb.empty()) {
int fnum = qf.size(), bnum = qb.size();
while (fnum--) {
int u = qf.front(); qf.pop();
int a = (u >> ) & 0xff, b = (u >> ) & 0xff, c = u & 0xff; for (int i = ; i < deg[a]; i++) {
int a2 = G[a][i];
for (int j = ; j < deg[b]; j++) {
int b2 = G[b][j];
if (conflict(a, b, a2, b2)) continue;
for (int k = ; k < deg[c]; k++) {
int c2 = G[c][k];
if (conflict(a, c, a2, c2) || conflict(b, c, b2, c2)) continue;
if (color[a2][b2][c2] == ) {
d1[a2][b2][c2] = d1[a][b][c] + ;
color[a2][b2][c2] = ;
qf.push(ID(a2, b2, c2));
}
else if (color[a2][b2][c2] == ) {
return d1[a][b][c] + d1[a2][b2][c2];
}
}
}
}
}
while (bnum--) {
int u = qb.front(); qb.pop();
int a = (u >> ) & 0xff, b = (u >> ) & 0xff, c = u & 0xff; for (int i = ; i < deg[a]; i++) {
int a2 = G[a][i];
for (int j = ; j < deg[b]; j++) {
int b2 = G[b][j];
if (conflict(a, b, a2, b2)) continue;
for (int k = ; k < deg[c]; k++) {
int c2 = G[c][k];
if (conflict(a, c, a2, c2) || conflict(b, c, b2, c2)) continue;
if (color[a2][b2][c2] == ) {
d1[a2][b2][c2] = d1[a][b][c] + ;
color[a2][b2][c2] = ;
qb.push(ID(a2, b2, c2));
}
else if (color[a2][b2][c2] == ) {
return d1[a][b][c] + d1[a2][b2][c2];
}
}
}
}
}
}
return -;
} int main() {
int w, h, n;
while (scanf("%d%d%d", &w, &h, &n) == , n) {
for (int i = ; i < h; i++) fgets(maze[i], , stdin);
int cnt = ;
int x[maxn], y[maxn];
int id[maxs][maxs];
for (int i = ; i < h; i++) {
for (int j = ; j < w; j++) {
if (maze[i][j] != '#') {
x[cnt] = i, y[cnt] = j, id[i][j] = cnt;
if (islower(maze[i][j])) s[maze[i][j] - 'a'] = cnt;
else if (isupper(maze[i][j])) t[maze[i][j] - 'A'] = cnt;
cnt++;
}
}
} for (int i = ; i < cnt; i++) {
for (int j = ; j < ; j++) {
int xx = x[i] + dx[j], yy = y[i] + dy[j];
if (maze[xx][yy] != '#') G[i][deg[i]++] = id[xx][yy];
}
} if (n <= ) {
deg[cnt] = ;
G[cnt][] = cnt;
s[] = t[] = cnt++;
}
if (n <= ) {
deg[cnt] = ;
G[cnt][] = cnt;
s[] = t[] = cnt++;
} memset(d1, , sizeof d1);
memset(color, , sizeof color); if (s[] == t[] && s[] == t[] && s[] == t[]) printf("0\n");
else printf("%d\n", bfs());
}
return ;
}

UVA 1601 双向BFS的更多相关文章

  1. 【UVa】1601 The Morning after Halloween(双向bfs)

    题目 题目     分析 双向bfs,对着书打的,我还调了好久.     代码 #include<cstdio> #include<cstring> #include<c ...

  2. UVA - 1601 The Morning after Halloween (双向BFS&单向BFS)

    题目: w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...

  3. UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS && 降维 && 状压)

    题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...

  4. UVA - 11624 Fire! 双向BFS追击问题

    Fire! Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of ...

  5. <<操作,&0xff以及|的巧妙运用(以POJ3523---The Morning after Halloween(UVa 1601)为例)

    <<表示左移,如a<<1表示将a的二进制左移一位,加一个0,&0xff表示取最后8个字节,如a&0xff表示取a表示的二进制中最后8个数字组成一个新的二进制数, ...

  6. POJ1915Knight Moves(单向BFS + 双向BFS)

    题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...

  7. HDU 3085 Nightmare II 双向bfs 难度:2

    http://acm.hdu.edu.cn/showproblem.php?pid=3085 出的很好的双向bfs,卡时间,普通的bfs会超时 题意方面: 1. 可停留 2. ghost无视墙壁 3. ...

  8. POJ 3170 Knights of Ni (暴力,双向BFS)

    题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...

  9. [转] 搜索之双向BFS

    转自:http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx 如果目标也已知的话,用双向BFS能很大程度上提高速度. 单向时,是 b^le ...

随机推荐

  1. 最近公共祖先(LCA)问题

    目录 最近公共祖先 1.向上标记法 2.树上倍增法 3.Tarjan算法 最近公共祖先 定义:给定一颗有根树,若结点 z 既是 x 的祖先,也是 y 的祖先,则称 z 是 x,y 的公共祖先.在 x, ...

  2. Encoding.UTF8 与 new UTF8Encoding(false) 有什么区别?

    System.Text.Encoding.UTF8 是一个静态实例,它省略了 BOM,而 new UTF8Encoding(false) 创建的实例是含有 BOM 的. BOM,即 Byte Orde ...

  3. Linux系统下安装python3.7.3环境

    这里用到的Linux系统是centos7系统,centos7是自带py的但是py的2.7.5版本 连接服务器的使用的是SSH Secure shell 1.首先安装依赖包 1)安装gcc编译器 gcc ...

  4. e_book

    1. 奢侈的纸制书籍 2. 电子书 2.1 与印刷书籍的比较 2.2 电子书格式 2.2.1 Kindle 2.2.2 PDF 2.2.3 EPUB 2.2.4 更多电子书格式比较 2.3 公共领域的 ...

  5. CMake构建Qt5的VS2015项目 (Hello Qt5)

    Qt5的编译 Windows下载编译Qt5 Gui CMakeLists.txt 源码 cmake_minimum_required(VERSION 2.8.11) project(HelloQt5) ...

  6. 第一个Vue-cli创建项目

    需要环境: Node.js:http://nodejs.cn/download/ 安装完成之后,使用cmd测试: 我现在的是最新的 安装Node.js加速器: 这个下载的稍微慢一些 npm insta ...

  7. Centos7 mariadb (mysql)主从复制实现

    一.mysql基本命令 .启动mysql systemctl start mariadb .linux客户端连接自己 mysql -uroot -p -h 127.0.0.1 .远程链接mysql服务 ...

  8. Xcode下载途径

    Xcode除了能在Appstore直接下载外,还可以用开发者账号登陆开发者中心[https://developer.apple.com/download/]下载对应的资源. 在开发者中心下载的好处是, ...

  9. 二 基于java动态数组手写栈

    package dataStucture2.stack; import dataStucture2.array.MyDynamicArray; /** * 基于动态数组手写栈 * 设计时,栈中仅栈顶对 ...

  10. 《React后台管理系统实战 :一》:目录结构、引入antd、引入路由、写login页面、使用antd的form登录组件、form前台验证、高阶函数/组件

    实战 上接,笔记:https://blog.csdn.net/u010132177/article/details/104150177 https://gitee.com/pasaulis/react ...