UVa1601 The Morning after Halloween (双向广度优先搜索)

链接:http://acm.hust.edu.cn/vjudge/problem/51163分析:已知起点和终点可以利用双向广度优先搜索,正向扩展一层,反向扩展一层,为防止退化,优先扩展结点数多的方向。因为障碍物很多防止TLE,可以先把图除了‘#’抠下来,用cnt给位置编号,x[cnt],y[cnt]为编号为cnt的格子的横纵坐标,id记录坐标为x,y格子的编号,然后找这些格子周围能走的格子,用deg[cnt]保存编号为cnt的格子周围能走的格子数,用G[cnt][i]保存编号为cnt的格子周围能走的第i个格子的编号,如果鬼的数量不足3,可以通过增加虚拟的格子,凑3个鬼,用来凑的鬼放在这个虚拟的格子里,并且设起点终点都是这个虚拟格子,且移动的方式只能原地不动。最后两个方向相遇两个d相加即求出最短路。
 1 #include <cstdio>
 2 #include <cctype>
 3 #include <queue>
 4 #include <cstring>
 5 using namespace std;
 6
 7 const int maxn = 150;
 8 const int maxs = 20;
 9 int w, h, n, deg[maxn], G[maxn][5], s[3], t[3];
10 char maze[20][20];
11 int d[maxn][maxn][maxn];
12 int d2[maxn][maxn][maxn];
13
14 inline int ID(const int& a, const int& b, const int& c) {
15     return (a << 16) | (b << 8) | c;
16 }
17
18 inline bool conflict(const int& a, const int& b, const int& a2, const int& b2) {
19     return a2 == b2 || (a2 == b && b2 == a);
20 }
21
22 int DBfs() {
23     queue<int> q;
24     queue<int> q2;
25     queue<int> nxt;
26     memset(d, -1, sizeof(d));
27     memset(d2, -1, sizeof(d2));
28     q.push(ID(s[0], s[1], s[2]));
29     q2.push(ID(t[0], t[1], t[2]));
30     d[s[0]][s[1]][s[2]] = 0;
31     d2[t[0]][t[1]][t[2]] = 0;
32     while (!q.empty() && !q2.empty()) {
33         if (q.size() > q2.size()) swap(q, q2), swap(d, d2);
34         for (int ii = 0, sz = q.size(); ii < sz; ii++) {
35             int u = q.front(); q.pop();
36             int a = (u >> 16) & 0xff; int b = (u >> 8) & 0xff; int c = u & 0xff;
37             for (int i = 0; i < deg[a]; i++) {
38                 int a2 = G[a][i];
39                 for (int j = 0; j < deg[b]; j++) {
40                     int b2 = G[b][j];
41                     if (conflict(a, b, a2, b2)) continue;
42                     for (int k = 0; k < deg[c]; k++) {
43                         int c2 = G[c][k];
44                         if (conflict(a, c, a2, c2)) continue;
45                         if (conflict(b, c, b2, c2)) continue;
46                         if (d[a2][b2][c2] != -1) continue;
47                         d[a2][b2][c2] = d[a][b][c] + 1;
48                         if (d2[a2][b2][c2] >= 0) return d[a2][b2][c2] + d2[a2][b2][c2];
49                         nxt.push(ID(a2, b2, c2));
50                     }
51                 }
52             }
53         }
54         swap(q, nxt);
55     }
56     return -1;
57 }
58
59 const int dx[5] = {1, -1, 0, 0, 0};
60 const int dy[5] = {0, 0, 1, -1, 0};
61 void init() {
62     int cnt = 0, x[maxn], y[maxn], id[maxs][maxs];
63     for (int i = 0; i < h; i++)
64         for (int j = 0; j < w; j++)
65             if (maze[i][j] != ‘#‘) {
66                 x[cnt] = i; y[cnt] = j; id[i][j] = cnt;
67                 if (islower(maze[i][j])) s[maze[i][j] - ‘a‘] = cnt;
68                 else if (isupper(maze[i][j])) t[maze[i][j] - ‘A‘] = cnt;
69                 cnt++;
70             }
71     for (int i = 0; i < cnt; i++) {
72         deg[i] = 0;
73         for (int dir = 0; dir < 5; dir++) {
74             int nx = x[i] + dx[dir], ny = y[i] + dy[dir];
75             if (nx < 0 || nx >= h || ny < 0 || ny >= w) continue;
76             if (maze[nx][ny] != ‘#‘) G[i][deg[i]++] = id[nx][ny];
77         }
78     }
79     if (n <= 1) { deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++; }
80     if (n <= 2) { deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++; }
81 }
82
83 int main() {
84     while (scanf("%d%d%d\n", &w, &h, &n) == 3 && n) {
85         for (int i = 0; i < h; i++)
86             fgets(maze[i], 20, stdin);
87         init();
88         printf("%d\n", DBfs());
89     }
90     return 0;
91 }
时间: 2024-08-04 22:15:25

UVa1601 The Morning after Halloween (双向广度优先搜索)的相关文章

八数码问题——双向广度优先搜索解决

八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移.空格右移.空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态. 搜索顺序有两种: (1)两个方向交替进行扩展 (2)每次选择节点少的那个扩展 一般来说方法(2)可以克服两端生长不平衡的现象 // eight.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<vector> #include&l

UVa1601 - The Morning after Halloween(单向+双向BFS)

给出一个最大为16×16的迷宫图和至多3个ghost的起始位置和目标位置,求最少经过几轮移动可以使三个ghost都到达目标位置.每轮移动中,每个ghost可以走一步,也可以原地不动,需要注意的是任意两个ghost不能在相同的位置,因此也不能出现任意两个ghost对穿,也就是原来是ab,移动之后是ba.每个迷宫图'#'表示墙,' '表示空地,小写字母表示ghost的起始位置,大写字母表示对应ghost的目标位置,比如'a'应该走到'A'.保证任意2×2的空间内都有一个'#'. 看起来就像是人数多了

理解广度优先搜索

1.   定义 BFS是Breath First Search的缩写,是广度优先搜索的意思,是图的遍历方式的一种. 由于BFS是从起点一层一层的进行搜索的,所以凡是需要求最短路径的问题,都可以尝试看BFS能否解决,比如Dijkstra的单源最短路径算法使用了BFS的思想.另外,在执行广度优先搜索的过程中将构造出一棵树,这也是Prim的最小生成树算法思想.在做BFS的时候,有两点需要特别注意: 1.      为了防止搜索进入无限循环,节点需要判重,也就是已经访问过的节点不要再访问了,所以需要记录

广度优先搜索-最少转机次数

当你和家人一起去海南旅游,可是你的城市并没有直接到达海南的飞机,但是你已经搜集了很多航班的信息,现在你希望找到一种乘坐方式,使得转机次数最少 如何解决呢? 假如你的城市在1号城市,海南在5号城市:现有如下关系: 如何求得1号城市到5号城市的最少转机次数呢?此时就用到了本次讲解的内容,广度优先搜索! 作图的问题首先我们应该用邻接矩阵或者二维数组来存取顶点之间的关系. 广度优先搜索需要用队列来存储每次扩展的关系. 首先将1号城市入队,通过1号城市我们可以扩展出2号和3号城市,2号城市又可以扩展出3号

深度优先搜索和广度优先搜索的深入讨论

一.深度优先搜索和广度优先搜索的深入讨论 (一)深度优先搜索的特点是: (1)从上面几个实例看出,可以用深度优先搜索的方法处理的题目是各种各样的.有的搜索深度是已知和固定的,如例题2-4,2-5,2-6:有的是未知的,如例题2-7.例题2-8:有的搜索深度是有限制的,但达到目标的深度是不定的. 但也看到,无论问题的内容和性质以及求解要求如何不同,它们的程序结构都是相同的,即都是深度优先算法(一)和深度优先算法(二)中描述的算法结构,不相同的仅仅是存储结点数据结构和产生规则以及输出要求. (2)深

【算法】广度优先搜索

广度优先搜索(breadth first search) 图 最短路径问题(shorterst-path problem) 解决最短路径问题的算法被称为广度优先搜索. 最短路径问题解决步骤 (1) 使用图来建立问题模型. (2) 使用广度优先搜索解决问题. 图的定义 图模拟一组连接. 图由节点(node)和边(edge)组成.一个节点可能与众多节点直接相连,这些节点被称为邻居.图用于模拟不同的东西是如何相连的. 广度优先搜索 广度优先搜索是一种用于图的查找算法,可帮助回答两类问题. 第一类问题:

深度优先搜索和广度优先搜索的比较与分(转)

深度优先搜索和广度优先搜索的深入讨论   (一)深度优先搜索的特点是: (1)无论问题的内容和性质以及求解要求如何不同,它们的程序结构都是相同的,即都是深度优先算法(一)和深度优先算法(二)中描述的算法结构,不相同的仅仅是存储结点数据结构和产生规则以及输出要求. (2)深度优先搜索法有递归以及非递归两种设计方法.一般的,当搜索深度较小.问题递归方式比较明显时,用递归方法设计好,它可以使得程序结构更简捷易懂.当搜索深度较大时,当数据量较大时,由于系统堆栈容量的限制,递归容易产生溢出,用非递归方法设

广度优先搜索(BreadthFirstSearch)&amp; 迪克斯特拉算法 (Dijkstra&#39;s algorithm)

BFS可回答两类问题: 1.从节点A出发,有前往节点B的路径吗? 2.从节点A出发,前往节点B的哪条路径经过的节点最少? BFS中会用到“队列”的概念.队列是一种先进先出(FIFO, first in first out)的数据结构,与栈不同,栈是后进先出(LIFO, last in first out)的数据结构. 还会用到“字典”的概念.字典在现在很多语言中都存在且广泛使用,字典中的元素是一组<键(key),值(value)>对,key的值是不可以重复的.关于字典的详细内容,网上有很多资料

无向图的深度优先与广度优先搜索代码实现

图采用了邻接表的形式储存. 带不带权都无所谓的 深度优先搜索 Depth First Search 道理和树的先序遍历差不多,把将要访问的点入栈,然后从栈里取点进行访问. 由于这只是类中的一个成员函数,有些被调用的函数的具体代码将会在文章最后补上 ,但是函数功能看注释就好了 1 //深度优先 2 void GraphAdjacencyListWeight::DFSAdvanced(int StartVertex) { 3 int *visited = new int[VertexNumber];