关键点
判断一个节点是否被访问(即剪枝)的三个要素:行号、列号、连续跨越的格子数
(因为一个行列坐标可能被多次访问,有可能在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";
}