Uva1600 巡逻机器人

题目描述:

机器人从一个\(m\times n\)网格的左上角\((1,1)\)走到右下角\((m,n)\)。网格中的一些格子是空地,用\(0\)表示,其他格子是障碍,用\(1\)表示。机器人每次可以往四个方向走一格,但不能连续地穿越\(k\)个障碍,求最短路的长度。起点和中点保证是空地。

思路:

还是BFS求最短路,但是因为不能连续穿过\(k\)个障碍,所以与普通BFS不同的是这里需要考虑到达某个格子时已经连续走了几个障碍,而且即使格子已经被访问过,但如果新的访问耗费的障碍数能小于此前访问耗费的障碍数,也是可以访问的(与普通BFS的区别在这里)。后面这点是我开始没有想到,后面对着udebug上的测试数据调的时候才发现问题的,还有就是要考虑一下\(m=1,n=1\)的初始条件。

代码:

#include <iostream>
#include <queue>
#include <utility>
#include <algorithm>
#include <memory.h> 
using namespace std;
const int maxn = 20 + 2;
int b[maxn][maxn];
int d[maxn][maxn];
int obs[maxn][maxn];
int m, n, k;

const int dr[] = { 0, -1, 0, 1};
const int dc[] = { 1, 0, -1, 0};

pair<int, int> walk(pair<int, int> u, int i){
    pair<int, int> v;
    v.first = u.first + dr[i];
    v.second = u.second + dc[i];
    return v;
}

void solve(){
    queue<pair<int, int> > q;
    q.push(make_pair(1, 1));
    memset(d, -1, sizeof(d));
    memset(obs, 0, sizeof(obs));
    d[1][1] = 0;
    while(!q.empty()){
        pair<int, int> u = q.front(); q.pop();
        for(int i = 0; i < 4; ++i){
            pair<int, int> v = walk(u, i);
            if(v.first == m && v.second == n) { //抵达终点
                d[v.first][v.second] = d[u.first][u.second] + 1;
                printf("%d\n", d[v.first][v.second]); 
                return;
                }
            if(v.first > 0 && v.first <= m && v.second > 0 && v.second <= n && (d[v.first][v.second]<0||d[v.first][v.second]>0&&obs[u.first][u.second]+1<obs[v.first][v.second])){  //没有出界&&(没有被访问过||访问过但是当前路径到达这个点时耗费的障碍数更少)
                d[v.first][v.second] = d[u.first][u.second] + 1;//更新起点到达该网格的距离
                if(b[v.first][v.second] == 1){ //如果网格是一个障碍 
                    obs[v.first][v.second] = obs[u.first][u.second] + 1;//获得当前网格连续经过的障碍数
                    if(obs[v.first][v.second] > k) { d[v.first][v.second] = -1;  obs[v.first][v.second] = 0; continue;}//如果障碍数超过限制,将这个网格标记为没有访问,重新将其状态初始化。 
                }
                else obs[v.first][v.second] = 0; //不是网格就清零连续障碍数
                q.push(v);
            }
        }
    }
    if(d[m][n] < 0) printf("-1\n");//最终没能访问到终点,输出-1
    else printf("%d\n", d[m][n]); //这里是应对m=1,n=1的边界条件
}

int main(){
    //freopen("uva1600_in.txt", "r", stdin);
    //freopen("uva1600_out.txt", "w", stdout);
    int T; scanf("%d", &T);
    while(T--){
        scanf("%d%d%d", &m, &n, &k);
        for(int i = 1; i <= m; ++i){
            for(int j = 1; j <= n; ++j)
                scanf("%d", &b[i][j]);
        }
        solve();
    }
}

猜你喜欢

转载自www.cnblogs.com/patrolli/p/11299838.html