UVA-1600-Patrol Robot

关键点

判断一个节点是否被访问(即剪枝)的三个要素:行号、列号、连续跨越的格子数

(因为一个行列坐标可能被多次访问,有可能在bfs同一层,有可能在不同层。只看行列坐标会扼杀可能性,比如有一次的访问,连续跨越数可能到达了最大值,刚好一圈都是障碍物,就走不下去,导致输出-1;而走其他路径的另一次访问可能连续跨越数不同了,这个点就能走通了)

AC代码

/*
 * 关键在于剪枝,即vst数组
 * 格子被访问过,当且仅当:行号与列号被访问过且连续跨越的格子数相同
 */
#include <iostream>
#include <queue>
#include <cstring>


using namespace std;

const int maxLen=22;
bool vst[maxLen][maxLen][maxLen];//行,列,连续跨越格子数
int map[maxLen][maxLen];
const int maxMoves=4;
int m,n,k;
//上下左右
int rows[]{-1,1,0,0};
int cols[]{0,0,-1,1};

struct node{
    int r,c,over;
    node(int r=0,int c=0,int over=0):r(r),c(c),over(over){}
    bool reach(){
        return this->r==m-1 && this->c==n-1;
    }
    bool legal(){
        return this->r>=0 && this->r<m
        && this->c>=0 && this->c<n
        && this->over<=k;
    }
};


void solve();

int main(){
    int T;
    cin>>T;
    while (T--){
        cin>>m>>n>>k;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                cin>>map[i][j];
            }
        }
            if(n==1 && m==1) { cout <<0<<"\n";continue; }
        solve();
    }
    return 0;
}

void solve() {
    memset(vst,0, sizeof(vst));
    int length=0;
    queue<node>q;
    node begin(0,0,0);
    vst[0][0][0]= true;
    q.push(begin);
    while (!q.empty()){
        int size=q.size();
        ++length;
        while (size--){
            node current=q.front();
            q.pop();
            for(int i=0;i<maxMoves;i++){
                int x=current.r+rows[i],y=current.c+cols[i];
                int over=0;
                //连续跨越
                if(map[x][y]){
                    ++over;
                    if(map[current.r][current.c]){
                        over+=current.over;
                    }
                }
                if(vst[x][y][over]) continue;
                node next(x,y,over);
                if(next.legal()){
                    vst[x][y][over]=true;
                    q.push(next);
                    if(next.reach()){
                        cout<<length<<"\n";
                        return;
                    }
                }
            }
        }
    }
    cout<<-1<<"\n";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值