这题可以用dfs写,我们记忆化搜索。
我们定义一个step和time数组,分别表示走到这点的最小步数,time表示走到该点炸弹还剩多少时间。
递归边界一是,如果走到该点,时间等于0,我们就返回。
如果走到了终点并且我们这次走到这点的最小步数小于了之前的答案,我们就更新答案并返回。
剪枝,首先越界剪枝,然后我们走到一点,不能步数增加了,并且上一次我们走这点炸弹的剩余时间pre,小于这次的炸弹剩余时间now。
那样的话,我们不如不走,我们还可以知道我们如果走到这点,步数和上一次相同,剩余时间也相同,我们就不必再搜这点,所以有两个等于。
然后我们更新步数和时间,更新之后再来判断,此时我们走到下一个房间,是否能够重置时间,可以就重置。
然后搜向下一个节点。
#include <cstdio> #include <cstring> const int INF=0x3f3f3f3f; int map[10][10],step[10][10],time[10][10]; int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; int n,m,ans; void dfs(int x,int y) { if (time[x][y]<=0) return; if (map[x][y]==3) { if (step[x][y]<ans) ans=step[x][y]; return ; } for (int i=0;i<4;i++) { int dx=x+d[i][0]; int dy=y+d[i][1]; if (dx>=0&&dy>=0&&dx<n&&dy<m&&map[dx][dy]) { if (step[x][y]+1>=step[dx][dy]&&time[x][y]-1<=time[dx][dy]) continue; step[dx][dy]=step[x][y]+1; time[dx][dy]=time[x][y]-1; if (map[dx][dy]==4&&time[dx][dy]>0) time[dx][dy]=6; dfs(dx,dy); } } } int main() { int t,sx,sy; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); for (int i=0;i<n;i++) { for (int j=0;j<m;j++) { scanf("%d",&map[i][j]); if (map[i][j]==2) sx=i,sy=j; } } memset(time,0,sizeof(time)); memset(step,INF,sizeof(step)); ans=INF; time[sx][sy]=6; step[sx][sy]=0; dfs(sx,sy); printf("%d ",ans==INF?-1:ans); } return 0; }