题目描述
机器人要从一个 m∗n(1<=m,n<=20) m ∗ n ( 1 <= m , n <= 20 ) 的网格的左上角 (1,1) ( 1 , 1 ) 走到右下角 (m,n) ( m , n ) 。网格中的一些格子是空地,其他格子是障碍(用 1 1 表示)。机器人每次可以往4个方向走一个,但不能连续地越过个障碍,求最短路。起点和终点保证是空地。
题解
题目中表示,机器人可以越过 k k 个障碍,那么一个值为1的网格就不一定是“障碍”。只有该网格是从前个值为1的网格走过来时,才为真正的“障碍”。 该题可用bfs求最短路径,对值为0和值为1的网格作不同处理。值为0的网格只保存其距起点的距离,值为1的网格多保存一个表示该障碍为第几个障碍的信息。这样将0和1都看作可以入队的点,进行遍历,而第 k+1 k + 1 个值为1的点不入队。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 100;
const int dx[4] = {1,0,-1,0};
const int dy[4] = {0,1,0,-1};
struct point{
int r, c;
point(int r = 0, int c = 0):r(r), c(c){}
};
int k, m, n;
bool mp[21][21];
int dis[21][21];
bool bfs(){
queue<point> qu;
while(!qu.empty()) qu.pop();
qu.push(point(0, 0));
while(!qu.empty()){
point s = qu.front();qu.pop();
for(int i = 0; i<4; i++){
int bx = s.r + dx[i], by = s.c + dy[i];
if(!(0<=bx&&bx<m&&0<=by&&by<n)) continue;
if(!mp[bx][by]){
if(dis[bx][by]) continue;
dis[bx][by] += ((dis[s.r][s.c]&0xffff) + 1);
}
else{
int a = ((dis[s.r][s.c]&0xffff) + 1), b = (dis[s.r][s.c]>>16)+1;
if(b>k || (dis[bx][by] <= (a|(b<<16)) && dis[bx][by])) continue;
dis[bx][by] = a|(b<<16);
}
qu.push(point(bx, by));
if(bx == m-1 && by == n-1) return true;
}
}
return false;
}
int solve(){
if(bfs()) return dis[m-1][n-1];
else if(n == 1 && m == 1) return 0;
else return -1;
}
int main(){
int T;
cin>>T;
while(T--){
memset(mp, 0, sizeof(mp));
memset(dis, 0, sizeof(dis));
cin>>m>>n>>k;
for(int i = 0; i<m; ++i)
for(int j = 0; j<n; ++j)
cin>>mp[i][j];
printf("%d\n", solve());
}
return 0;
}