题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1072
题目分析,这道题还是有点小难得,我拿到题还是思考了一会的。其实这道题就是说初始截止时间是6s,如果能在截止时间到0之前到达终点(这里个人觉得题目没有表述得很清楚,开始我默认的是如果在0时刻到达终点也算是可以的,结果提交之后就wrong answer了,改成到达终点的时候截止时间必须大于0就可以了),就输出走的最短的步数;或者到达一个标记为4的节点,截止时间就重置为6。
这里有一点要注意:因为每个节点可以重复遍历,所以不可能每一次遍历到一个节点就入栈,所以如果满足优化的条件才允许入栈,否则跳过。这个思想在另外一道题中也有体现。也是一个迷宫问题。大同小异,可参考对比。链接:http://blog.csdn.net/kay_zhyu/article/details/8736668。这里优化的条件就是,如果到达该节点的剩余时间有所增加,那么就把这个节点入队列。
为了避免标记为4的节点被反复遍历,标记为4的节点遍历一次之后,就置为0。这样就不会出现死循环了。
#include <stdio.h> #include<string.h> #define M 15 int map[M][M]; int used[M][M];//存放访问对应节点后的截止时间 int dp[M][M];//达到对应节点需要走的步数 int queue[2][5*M*M]; int derect[2][4] = {{0,1,0,-1},{1,0,-1,0}};//右,下,左,上 int BFS(int n, int m, int sx, int sy)//n行m列 { int head,tail; int i,x,y; int nx,ny; queue[0][0] = sx; queue[1][0] = sy; used[sx][sy] = 6; head = 0; tail = 1; while(head < tail) { x = queue[0][head]; y = queue[1][head]; for(i = 0; i < 4; ++i) { nx = x + derect[0][i]; ny = y + derect[1][i]; if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue; if(used[x][y] > 1 && map[nx][ny])//如果时间还有剩余,并且该点可通过 { if(map[nx][ny] == 3)//遇到终点就返回 return dp[x][y] + 1; if(map[nx][ny] == 4)//遇到4更新时间,并入队列 { used[nx][ny] = 6; queue[0][tail] = nx;//入队列 queue[1][tail++] = ny; map[nx][ny] = 0;//修改节点4,以免重复循环 dp[nx][ny] = dp[x][y] + 1; } if(used[x][y] - 1 > used[nx][ny]) { used[nx][ny] = used[x][y] - 1; queue[0][tail] = nx;//更新较优的数据,入队列 queue[1][tail++] = ny; dp[nx][ny] = dp[x][y] + 1; } } } ++head; } return -1; } void main() { int n,m; int i,j; int t; int sx,sy; int ans; scanf("%d",&t); while( t-- ) { scanf("%d %d",&n,&m); memset(dp,0,sizeof(dp)); memset(used, 0,sizeof(used)); for(i = 0; i < n; ++i) { for(j = 0; j < m; ++j) { scanf("%d",&map[i][j]); if(map[i][j] == 2) { sx = i; sy = j; } } } ans = BFS(n,m,sx,sy); printf("%d\n",ans); } }