巡逻机器人——UVa 1600
巡逻机器人(Patrol Robot, ACM/ICPC Hanoi 2006, UVa1600)#
机器人要从一个m*n(1≤m,n≤20)网格的左上角(1,1)走到右下角(m,n)。网格中的一些格子是空地(用0表示),其他格子是障碍(用1表示)。机器人每次可以往4个方向走一格,但不能连续地穿越k(0≤k≤20)个障碍,求最短路长度。起点和终点保证是空地。例如,对于图6-22(a)中的数据,图6-22(b)中显示的是最优解,路径长度为10。
输入#
第一行为pn,代表该组输入要处理几个问题。
下面有n组问题,每组的第一行是两个数,。
下面的一行为k,代表最大越过障碍数,。
下面的m行n列为输入的网格。
输出#
对于每组问题,输出一行,内容为起点到终点的最短路径。若起点到终点无法通达,输出-1。
输入输出示例#
Sample Input
4
6 7
2
0 0 0 0 0 0 0
0 1 0 1 0 1 0
0 0 1 1 0 0 0
1 1 1 0 0 1 0
0 1 1 1 1 1 1
0 0 0 0 0 0 0
2 5
0
0 1 0 0 0
0 0 0 1 0
4 6
1
0 1 1 0 0 0
0 0 1 0 1 1
0 1 1 1 1 0
0 1 1 1 0 0
2 2
0
0 1
1 0
Sample Output
7
10
-1
思路#
BFS应该都能想到,但是这个bfs有点不同,刚开始我搞了好久都是WA,也不知道错哪了。
我最开始的想法是和普通的bfs一样,但是对于网格中的每个位置记录一个pace
,代表走了多少步,然后如果这个位置是障碍物,并且已经超过k了,那么就不能走了。不过这个想法有些问题,欠考虑,一会再说。
queue<node> q
q.push(起点)
while(q.not_empty()){
n = q.pop();
// 如果n是终点
if(n is target){
return n.pace
}
for(adj : n.adjs){
// 如果在图中并且未访问过
if(inside(adj) && !vis(adj)){
// 如果是障碍物
if(g(adj)==OBJECT){
adj.pace = n.pace + 1
}
if(adj.pace > k) continue;
q.push(adj)
vis[adj] = 1
}
}
}
而真正的vis
应该与k关联,意思是不能这个网格访问过就不再访问了,而是如果下一次访问比上一次的步数小,就应该能访问。
考虑这个示例
1
2 9
2
0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 1 0
如果你的算法是按左下右上的方式遍历的,并且是vis未和k关联,那么将返回-1
,但是我们肉眼都能看到有一条通路。
因为按左上右下的方式遍历第2,2
个位置(下标从1开始)已经被1,2
标记为访问过了,所以从2,1
位置无法访问。
这个题目比较抽象,我马上要上课了,也懒得画图,脑袋里想想好了。
所以到这里基本思路就理清了,不能按传统的bfs的vis标记来做,应该把vis和k关联。
AC代码#
#include "iostream"
#include "cstdio"
#include "queue"
#include "cstring"
#define MAX 21
#define MAXK 21
using namespace std;
struct Node {
int x, y, k;
int pace;
Node(int x, int y, int k,int pace) : x(x), y(y), k(k), pace(pace){}
Node(){}
};
int pn,m,n,k;
int g[MAX][MAX];
int vis[MAX][MAX][21];
int dx[] = { 1,0,-1,0 };
int dy[] = { 0,1,0,-1 };
bool inside(Node node) {
return node.x > 0 && node.x <= m && node.y > 0 && node.y <= n;
}
int bfs() {
if (m == 1 && n == 1)return 0;
queue<Node>q;
q.push(Node(1,1,0,0));
memset(vis, 0, sizeof(vis));
while (!q.empty()) {
Node node = q.front(); q.pop();
if (node.x == m && node.y == n)return node.pace;
for (int i = 0; i < 4; i++) {
Node adj = Node(node.x + dx[i], node.y + dy[i],0,node.pace+1);
if (inside(adj)) {
// 计算连续走了多少个障碍
if (g[adj.x][adj.y])
adj.k = node.k + 1;
if (vis[adj.x][adj.y][adj.k])
continue;
if (adj.k <= k) {
q.push(adj);
vis[adj.x][adj.y][adj.k] = 1;
}
}
}
}
return -1;
}
void build() {
for(int i=1;i<=m;i++){
for (int j = 1; j <= n; j++) {
scanf("%d", &g[i][j]);
}
}
}
int main() {
scanf("%d", &pn);
for (int i = 0; i < pn; i++) {
scanf("%d %d", &m, &n);
scanf("%d", &k);
build();
int step = bfs();
printf("%d\n", step);
}
return 0;
}
作者:Yudoge
出处:https://www.cnblogs.com/lilpig/p/13995545.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
欢迎按协议规定转载,方便的话,发个站内信给我嗷~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)