(深搜)UVA - 1600 Patrol Robot

本文介绍了一道关于机器人路径寻找的题目,通过使用三维数组记录已访问的状态来优化搜索过程,确保找到最少障碍物的最短路径。文章分享了从DFS到BFS的思考过程及最终实现。

原题链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=825&page=show_problem&problem=4475


题意:

在m*n的地图上,有障碍物(1)和空地(0),机器人要通过走上下左右四个方向从左上角(1,1)走到右下角(n,m),但不能连续超过k个障碍,要求最短步数。


感悟:

刷紫书遇到的一题,一开始还很轻视的写了一个dfs,发现过不了样例,之后才发现是连续空格,稍微改下,过了样例就提交了,结果是TLE。评估下,要么就是dfs中判断的不够严格,需要剪枝,要么就是这题dfs必定超时,只能用bfs。先尝试前一种,发现平从我定义的状态中以我的水无法再优化剪枝,思考了一下bfs,感觉按照我dfs的思路,写出来的bfs必定WA。最后查看了题解,发现dfs,bfs都有人写,才知道自己在搜索上的造诣依然浅薄。


分析:

按照最基本的搜索题,我们都要定义一个vis二维数组,记录该点是否走过,并通过它达到回溯的目的。
但在这题中,机器人走路会有更多的分支选择,比如在走到同一点,有两种同一步数的走法,但是到达这一点所破除的障碍数量却不同,在这里我们需要选择障碍物更少的,因为很有可能在以后破除障碍能更快到达终点。用一个vis[][][]三维数组就可以记录这样一种状态,前两维记录坐标,第三维记录已经破除障碍物的数量,数组值表示走的步数,与上边一样的道理,到达相同点并且破除障碍物数量相同时,应该选择步数最小的。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <cctype>
#include <list>

#define ll long long
#define ull unsigned long long
#define VNAME(name) (#name)
#define debug(a) cout<<VNAME(a)<<" = "<<(a)<<endl;

using namespace std;

const int maxn = 100010;
const int inf = 1 << 30;

int maps[21][21];
int vis[21][21][21];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int n,m,k;
int ans;

int dfs(int x,int y,int step,int pok){
    if(x==n&&y==m){
        return step;
    }
    int ans=inf;
    for(int i=0;i<4;i++){
        int tx=x+dx[i];
        int ty=y+dy[i];
        int tp=pok;
        if(maps[tx][ty]==1)tp++;
        else tp=0;
        if(tx>=1&&tx<=n&&ty>=1&&ty<=m){
            if((vis[tx][ty][tp]<0||vis[tx][ty][tp]>step+1)&&tp<=k){
                vis[tx][ty][tp]=step+1;
                ans=min(ans,dfs(tx,ty,step+1,tp));
            }
        }
    }
    return ans;
}

int main() {
    //iostream::sync_with_stdio(false);

#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
#endif
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&maps[i][j]);
            }
        }
        memset(vis,-1,sizeof(vis));
        int ans=dfs(1,1,0,0);
        if(ans==inf){
            puts("-1");
        }
        else{
            printf("%d\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值