Uva 1600 Patrol Robot

题目:洛谷·UVa439 题意 输入一个m*n矩阵表示地图,其中1表示障碍,0表示空地。机器人要从m*n地图的(1,1)走到(m,n),每次可以往上下左右的其中一个方向走一格,且最多只能连续跨过k个障碍。数据满足1 <= m, n <= 20, 0 <= k <= 20 分析 首先我们可以确认这不是普通的BFS求最短路(对比:Uva 439),但题目多了一个条件——最多能连续跨过k个障碍,这意味着只用二位数组不足以判断题目条件 于是我试着用访问数组int vis[maxn][maxn][2]存储访问状态,其中vis[x][y][0]表示从该格再走一步后的步数,vis[x][y][1]表示走到该格需要跨越的障碍数。但这种思路存在问题:程序无法区分跨越不同数量的障碍走到同一格,而是把它们视为同一条路线 只需稍加改进,用bool vis[maxn][maxn][maxn]存储访问状态即可,其中vis[x][y][cnt]表示连续跨越cnt个障碍后到达(x,y) 利用结构体存储坐标、步数和连续跨越障碍的数量,方便BFS的入队出队操作(因为只需一个队列) 代码 C++ #include <iostream> #include <queue> #include <cstring> using namespace std; const int maxn = 25; int pic[maxn][maxn]; // 读入地图 bool vis[maxn][maxn][maxn]; // 访问数组,判断是否曾连续跨过若干个障碍到达某格 const int dx[4] = {0, 1, 0, -1}; // 偏移量 const int dy[4] = {1, 0, -1, 0}; int t, m, n, k; struct Node { int x; int y; int step; // 当前步数 int cnt; // 当前连续跨越障碍的数量 }; void read_lines() { cin >> m >> n >> k; for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) cin >> pic[i][j]; } bool check(int x, int y) { // 检查是否出界 if (x < 1 || y < 1 || x > m || y > n) return true; return false; } int bfs(int x, int y, int k) { Node t = {x, y, 0, 0}; queue<Node> q; q.push(t); while (!q.empty()) { t = q.front(); if (t.x == m && t.y == n) return t.step; for (int i = 0; i < 4; i++) { int px = t.x + dx[i], py = t.y + dy[i]; if (check(px, py)) continue; // 出界 Node tmp = {px, py, t.step, t.cnt}; // 一定要用临时变量来操作! if (pic[px][py]) tmp.cnt++; // 该格为障碍 else tmp.cnt = 0; // 该格为空地 if (tmp.cnt <= k && !vis[px][py][tmp.cnt]) { // 连续跨越障碍数量<=k且未曾连续跨过t.cnt个障碍到达(px,py) tmp.step++; vis[px][py][tmp.cnt] = true; // 已访问 q.push(tmp); } } q.pop(); } return -1; } int main() { #ifdef LOCAL freopen("patrol_robot.in", "r", stdin); freopen("patrol_robot.out", "w", stdout); #endif ios::sync_with_stdio(false); //取消cin与stdin的同步,加速输入输出 cin.tie(0); // 解除cin与cout的绑定,进一步加快执行效率 cout.tie(0); cin >> t; while (t--) { memset(vis, false, sizeof(vis)); // 记得清零! read_lines(); cout << bfs(1, 1, k) << "\n"; } return 0; } 我们知道cin和cout输入输出的速度比不上printf和scanf,因此可以通过一些小技巧来加速: ...

2023/01/11 · Allen Wu

生成和检查的有机结合-回溯法

减少不必要的枚举

2022/12/03 · Allen Wu

数据结构之美-二叉树

最近看什么都像二叉树(

2022/11/06 · Allen Wu

数据结构初见-栈

简单而又不简单

2022/10/30 · Allen Wu

最“简单”的算法——贪心算法

这破题我写了三天.jpg

2022/10/07 · Allen Wu

Python生成多项式与牛顿法

Python 与数学的碰撞

2022/10/02 · Allen Wu

C语言初学者的汉诺塔

引言 在印度,有这样一个古老的传说。在世界中心贝拿勒斯的圣庙里, 一块黄铜板上插着3根宝石针。印度教的主神梵天在创造世界的时候, 在其中一根针上从下到上地穿好了由大到小的64片金盘, 这就是所谓的汉诺塔(Tower of Hanoi)。 不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金盘到另一根针上: 一次只移动一片,而且小片必在大片上面。 当所有的金盘都从梵天穿好的那根针上移动到第三根针上时, 世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽…… 分析问题 什么是汉诺塔 总结如下: 有 A, B, C 三根柱子,A 柱上有 n(n > 1) 个金盘,金盘的尺寸由下到上依次变小。 每次只能移动一片金盘,且大金盘不能位于小金盘之上,使得所有金盘都移动到 C 柱。 问:如何移?最少要移动多少次? 一个最简单的例子 当 n = 1 时,只需1步就能解决:A-->C ( A-->C 表示把 A 柱最上面的一个金盘移动到 C 柱,下同) 一个很简单的例子 当 n = 2 时,只需3步: A-->B A-->C B-->C 一个简单的例子 当 n = 3 时,用一张图来解决: 用语言表述如下: A-->C A-->B C-->B A-->C B-->A B-->C A-->C 共需7步 扩展到 n 当 n = 4, 5, 6 甚至 20 时,又该怎么办呢? 这个问题看起来很复杂,其实是有规律可循的 根据数学方法计算得出,移动 n 层的汉诺塔所需次数为 $2^n - 1$ ...

2022/09/11 · Allen Wu