题目链接: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);
}
}