但是我们还不是很清楚每一次的状态怎么储存?我们可以用一个结构体,将每次的位置存起来,但是这个程序中用了一个更好的储存方法:我们知道最大的格数是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. jdk 档案库(包含历史版本)

    http://java.sun.com/products/archive/ 参考:https://blog.csdn.net/shiluyong8068/article/details/7894747 ...

  2. SWD学习笔记

    SWD其实和JTAG类似,是一种调试串口. JTAG大致了解了一下.JTAG(Joint Test Action Group)主要4 lines:TMS(模式选择),TCK(时钟),TDI(数据输入) ...

  3. The Google File System中文版

    译者:alex 摘要 我们设计并实现了Google GFS文件系统,一个面向大规模数据密集型应用的.可伸缩的分布式文件系统.GFS虽然运行在廉价的普遍硬件设备上,但是它依然了提供灾难冗余的能力,为大量 ...

  4. Lesson 13 The search for oil

    What do oilmen want to achieve as soon as they strike oil? The deepest holes of all are made for oil ...

  5. 为什么阿里Java规约要求谨慎修改serialVersionUID字段

    serialVersionUID简要介绍 serialVersionUID是在Java序列化.反序列化对象时起作用的一个字段.Java的序列化机制是通过判断类的serialVersionUID来验证版 ...

  6. 六 一对多关联查询&关联查询小结

    一对多关联查询:基于用户表关联查询订单表 在pojo中,一的一方方式多的一方的集合 在代理映射中配置查询方法,ResultMap一对多关系(注意:当两表有字段重名时,在一方字段设置别名,以免造成查询混 ...

  7. Day9 - C - Bookshelf 2 POJ - 3628

    Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled u ...

  8. Java中的输入"scanf",Scanner用法

    1.输入程序 1)Scnner的初始用法: 1 import java.util.Scanner; 2 public class Textone { 3 public static void main ...

  9. 【C#】关于左移/右移运算符的使用

    吐槽先~为什么我的老师大学时候没教过我这东西  - -. 继续送栗子: 比如 “(1+2)<<3” 你们猜等于几~ Debug.Log((1+2)<<3)之后输出的是“24”. ...

  10. 1_01_MSSQL课程_基础入门

    0. 课程安排: 课程共7天课,前两天SQL基础,后面三天Ado.Net ,最后两天数据库高级进阶学习. 1.数据库的概念 ->数据库就是数据仓库. ->DBMS:数据库管理系统.SQLS ...