Loading

巡逻机器人——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组问题,每组的第一行是两个数,\(m,n(1<=m,n<=20)\)

下面的一行为k,代表最大越过障碍数,\(0<=k<=20\)

下面的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;
}
posted @ 2020-11-17 17:56  yudoge  阅读(133)  评论(0编辑  收藏  举报