乍一看是迷宫最短路问题,用BFS,DFS都可以解决。这道题的特点是有重置,在走迷宫求最短路径这个根本目的不变的同时,要求如果没有重置炸弹或者到达出口不能连续移动超过5次。
地图大小并不大(<=8),时间要求1000ms。首先考虑DFS搜索是否可行,第一次提交的是标准DFS搜索,遇到炸弹重置点重置剩余可走步数,超出范围或者超出可走步数返回搜索。然而超时了,有许多冗余调用没有提前退出,因此使用矩阵记忆每次搜索过的该点历史最短步数和最多剩余时间。当再一次搜索至该点时,如果此次搜索的步数和时间均比历史记录差,则放弃继续搜索。
这次调整后成功通过,OJ计时仅1ms,说明去冗效果还是很不错的。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> #include<math.h> #include<limits.h> #define MAX 9 int map[MAX][MAX],step[MAX][MAX],time[MAX][MAX]; int n,m,minx; void dfs(int x,int y,int len,int cnt) { //printf("DFS***x=%d,y=%d,len=%d,cnt=%d,step=%d,time=%d\n",x,y,len,cnt,step[x][y],time[x][y]); if(x<0 || y<0 || x>=n || y>=m) return; if(len<=0 || cnt>=minx) return; if(map[x][y]==0) return; if(map[x][y]==3) { if(cnt<minx) minx=cnt; return; } if(map[x][y]==4) len=6; if(cnt>=step[x][y] && time[x][y]>=len) return; step[x][y]=cnt; time[x][y]=len; int tx,ty,i; int dir[4][2]={1,0,-1,0,0,1,0,-1}; for(i=0;i<4;i++) { tx=x+dir[i][0]; ty=y+dir[i][1]; dfs(tx,ty,len-1,cnt+1); } } int main(int argc,char* argv[]) { int num,i,j,len,cnt; scanf("%d",&num); while(num--) { scanf("%d %d",&n,&m); int sx,sy; for(i=0;i<n;++i) { for(j=0;j<m;++j) { time[i][j]=0; step[i][j]=INT_MAX-3; scanf("%d",&map[i][j]); if(map[i][j]==2) { sx = i; sy = j; } } } len = 6; cnt = 0; minx = INT_MAX; dfs(sx,sy,len,cnt); if(minx==INT_MAX) printf("-1\n"); else printf("%d\n",minx); } return EXIT_SUCCESS; }
用记忆化DFS解决,思路明确写起来还是比较容易的。但是用BFS实现肯定是更快,队列由地图XY坐标、已用时间和炸弹剩余时间组成。搜索的同时,当当前位置的炸弹剩余时间等于1的时候,跳过对当前位置的继续搜索。每走出一步都需要判断此次炸弹剩余时间是否多于历史时间,如果多于说明继续搜索是有意义的,并刷新炸弹剩余时间记录。如果一直没有搜索到终点则返回-1结束BFS搜索。OJ测试时间少于1ms。
#include<stdio.h> #include<stdlib.h> #include<string.h> struct node { int x,y; int time; int bomb; }; int map[9][9]; int book[9][9]; int BFS(int s1,int s2,int m,int n) { struct node que[81]; int move[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; int head=1; int body=1; que[body].x=s1; que[body].y=s2; que[body].time=0; que[body].bomb=6; body++; book[s1][s2]=6; while(head<body) { if(que[head].bomb-1==0) { head++; continue; } int i; for(i=0;i<4;i++) { int cx=que[head].x+move[i][0]; int cy=que[head].y+move[i][1]; if(cx<1||cx>m||cy<1||cy>n) continue; if(!map[cx][cy]) continue; if(book[cx][cy]<que[head].bomb) { if(map[cx][cy]==1||map[cx][cy]==3) { que[body].bomb=que[head].bomb-1; que[body].x=cx; que[body].y=cy; que[body].time=que[head].time+1; book[cx][cy]=que[body].bomb; body++; } else if(map[cx][cy]==4) { que[body].bomb=6; que[body].x=cx; que[body].y=cy; que[body].time=que[head].time+1; book[cx][cy]=6; body++; } if(map[que[body-1].x][que[body-1].y]==3) { return que[body-1].time; } } } head++; } return -1; } int main(int argc,char* argv[]) { int t; scanf("%d",&t); while(t--) { int i,j,s1,s2; int m,n; scanf("%d%d",&m,&n); for(i=1;i<=m;i++) { for(j=1;j<=n;j++) { scanf("%d",&map[i][j]); if(map[i][j]==2) { s1=i; s2=j; } } } memset(book,0,sizeof(book)); printf("%d\n", BFS(s1,s2,m,n)); } return 0; }
THE END