HDU1072——Nightmare(BFS)

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


你可能感兴趣的:(搜索,bfs)