hdu 1728 逃离迷宫 普通的队列 / 优先队列
来源:互联网 发布:python http get请求 编辑:程序博客网 时间:2024/06/06 01:00
题目链接
题意:
给定 m * n 的矩阵与起点终点位置, 限制转弯次数 k, 问能否到达终点
是个很显然的bfs, 但是
1. 要注意的是转弯无论一次转几个方向都是转一次, 一开始想当然的认为如果从(1, 0)方向转向(0, 1)方向就是转了两次, 结果一直WA...
2. 大概是因为是pascal入门所以一直对优先队列没什么概念, 而一直老老实实写普通的队列...但感觉大家都很直接的知道就是应该写优先队列
下面就来说一下两种不同的写法吧
(觉得优先队列写起来真是方便Orz
1.
如果是写一般的队列, 要注意用 num[i][j][dir] 来记录以方向 dir 来访问 map[i][j] 时用的最少步数,
不能直接开个 vis[i][j] 来记录是否访问过这个格子; 即使开了 vis[i][j][dir] 记录了是否以特定方向访问过某个格子, 也无法保证是最少的步数.
当且仅当步数少于 num[i][j][dir] 时将这个 node 给 push 进队列, 并且更新 num[i][j][dir].
从队头取出结点时, 如果其转弯数 num > num[i][j][dir] (即意味着在队列中的后面有更少的步数), 那就对其不作处理, 直接 pop 出去.
思路还是挺清楚的.
此外, 因为一直不能保证当前的 num 为最小值 (至少在我一开始以为一次性可以转两次的情况下...), 所以需要跑完整张图, 但是100 * 100还是很小的, 也没关系
AC代码如下:
#include <cstdio>#include <iostream>#include <queue>#include <cstring>#include <cmath>#define inf 0x3f3f3f3f#define maxn 110using namespace std;struct node { int x, y, num, dir;};queue<node> q;const int dx[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};int num[maxn][maxn][4], a[maxn][maxn], m, n;char s[maxn][maxn];inline min(int a, int b) { return a < b ? a : b; }void work() { for (int i = 1; i <= m; ++i) { scanf("%s", s[i]); } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (s[i][j - 1] == '.') a[i][j] = 0; else a[i][j] = 1; } } int k, x1, y1, x2, y2; scanf("%d%d%d%d%d", &k, &y1, &x1, &y2, &x2); memset(num, -1, sizeof(num)); for (int i = 0; i < 4; ++i) { num[x1][y1][i] = 0; int tx = x1 + dx[i][0], ty = y1 + dx[i][1]; if (tx > 0 && tx <= m && ty > 0 && ty <= n && !a[tx][ty]) { node temp; temp.x = tx; temp.y = ty; temp.num = 0; temp.dir = i; num[tx][ty][i] = 0; q.push(temp); } } while (!q.empty()) { node nowf = q.front(); int x = nowf.x, y = nowf.y, nnum = nowf.num, d = nowf.dir;// printf("%d %d\n", x, y); if (nnum <= num[x][y][d]) { for (int i = 0; i < 4; ++i) { int tx = x + dx[i][0], ty = y + dx[i][1]; if (tx > 0 && tx <= m && ty > 0 && ty <= n && !a[tx][ty]) { int tot; if (d == i) tot = nnum; else tot = nnum + 1;// int tot = min(abs(i - d), abs(4 - (i - d))) + nnum; if (num[tx][ty][i] == -1 || tot < num[tx][ty][i]) { num[tx][ty][i] = tot; node temp; temp.x = tx; temp.y = ty; temp.num = tot; temp.dir = i; q.push(temp); } } } } q.pop(); } int ans = inf; for (int i = 0; i < 4; ++i) if (num[x2][y2][i] != -1) ans = min(ans, num[x2][y2][i]); if (ans <= k) printf("yes\n"); else printf("no\n");// printf("%d\n", ans);}int main() {// freopen("1728.in", "r", stdin); int t; scanf("%d", &t); while (scanf("%d%d\n", &m, &n) != EOF) work(); return 0;}
2.
优先队列的话就可以保证一点, 那就是,
在下一次以这个方向访问这个节点时, 其值必然大于等于上一次的值,
故在取出队头时, 一旦其为终点, 必然就是转弯次数最少的结果, 就可以结束了.
因此, 有一点要注意, 就是跑下一组数据时, 必须要先 while (!q.empty()) q.pop();
并且此时就可以放心地用 vis[i][j][dir] 来表示是否以这个方向访问过这个位置了, 因为第一次访问必然是最优的访问
写起来也很好写 (挺短
AC代码如下:
#include <cstdio>#include <iostream>#include <queue>#include <cstring>#include <cmath>#define inf 0x3f3f3f3f#define maxn 110using namespace std;struct node { int x, y, num, dir; node(int xx = 0, int yy = 0, int nn = 0, int dd = 0) : x(xx), y(yy), num(nn), dir(dd) {} bool operator < (const node& b) const { return num > b.num; }};priority_queue<node> q;const int dx[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};int a[maxn][maxn], m, n;bool vis[maxn][maxn][4];char s[maxn][maxn];inline min(int a, int b) { return a < b ? a : b; }void work() { for (int i = 1; i <= m; ++i) { scanf("%s", s[i]); } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (s[i][j - 1] == '.') a[i][j] = 0; else a[i][j] = 1; } } memset(vis, 0, sizeof(vis)); int k, x1, y1, x2, y2; scanf("%d%d%d%d%d", &k, &y1, &x1, &y2, &x2); while (!q.empty()) q.pop(); for (int i = 0; i < 4; ++i) q.push(node(x1, y1, 0, i)); while (!q.empty()) { node nowf = q.top(); q.pop(); int x = nowf.x, y = nowf.y, num = nowf.num, d = nowf.dir;// printf("%d %d %d\n", x, y, num); if (num > k) { printf("no\n"); return; } if (x == x2 && y == y2) { printf("yes\n"); return; } if (vis[x][y][d]) continue; vis[x][y][d] = true; for (int i = 0; i < 4; ++i) { int tx = x + dx[i][0], ty = y + dx[i][1]; if (tx > 0 && tx <= m && ty > 0 && ty <= n && !a[tx][ty] && !vis[tx][ty][d]) { int tot = num; if (d != i) ++tot; q.push(node(tx, ty, tot, i)); } } } printf("no\n");}int main() {// freopen("1728.in", "r", stdin); int t; scanf("%d", &t); while (scanf("%d%d\n", &m, &n) != EOF) work(); return 0;}
- hdu 1728 逃离迷宫 普通的队列 / 优先队列
- hdu 1728 逃离迷宫(dFS+优先队列)
- hdu 1728 逃离迷宫(搜索:BFS+优先队列)
- hdu 1728 逃离迷宫 (bfs+循环队列)
- 逃出迷宫 优先队列
- HDOJ/HDU 1728 逃离迷宫 DFS 深度优先搜素
- HDU 1728 逃离迷宫
- HDU 1728 逃离迷宫
- hdu 1728 逃离迷宫
- hdu 1728 逃离迷宫
- hdu 1728 逃离迷宫
- hdu 1728 逃离迷宫
- HDU-1728 逃离迷宫
- hdu 1728 逃离迷宫
- HDU 1728 逃离迷宫
- hdu 1728 逃离迷宫
- Hdu 1728 逃离迷宫
- hdu 1728 逃离迷宫
- <JavaScript>Basic
- 调用startActivityForResult之后,onActivityResult立即响应
- Android Wi-Fi Wi-Fi联盟PMK Caching认证简介
- 【NKOJ3958/BZOJ2693】【莫比乌斯反演】jzptab
- 51Nod-1719-数值计算
- hdu 1728 逃离迷宫 普通的队列 / 优先队列
- HDU
- Linux桌面环境与命令行环境切换快捷键
- 第一篇= =
- Material Design之滑动菜单
- 28BYJ的一点收获
- 20. nginx 服务器的邮件服务
- nginx服务配置
- Hdu 3555