Hduoj1728【搜索+DP】

/*逃离迷宫 
Time Limit : 1000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 0   Accepted Submission(s) : 0
Font: Times New Roman | Verdana | Georgia 
Font Size: ← →
Problem Description
  给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,
有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,
gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,
gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗? 
Input
  第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,
  第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,
字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x1, y1, x2, y2 
(1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,
y1, y2对应行。

Output
  每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。 
Sample Input
2
5 5
...**
*.**.
.....
.....
*....
1 1 1 1 3
5 5
...**
*.**.
.....
.....
*....
2 1 1 1 3

Sample Output
no
yes
Source
“网新恩普杯”杭州电子科技大学程序设计邀请赛 
*/
#include<stdio.h>
char map[110][110];
int m, n,  dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0}, x1, y1, x2, y2, f[110][110], dir[110][110], k;
void dfs(int x, int y)
{
	int nx , ny, i, j;
	if(x == y2 && y == x2)//end
		return ;
	for(i = 0; i < 4; ++i)
	{
		nx = x + dx[i];
		ny = y + dy[i];
		if(nx >= 0 && nx < m && ny >= 0 && ny < n && map[nx][ny] != '*' )
		{
			if(dir[x][y] != i + 1)
			{
				if(f[x][y] + 1 <= f[nx][ny] && f[x][y] + 1 <= k)//use the f[] to save the minimum corners 
				{                               //use the dir[] to save the direction
					f[nx][ny] = f[x][y] + 1;
					dir[nx][ny] = i+1;
					dfs(nx,ny);
				}
			}
			else
			{
				if(f[x][y] <= f[nx][ny] && f[x][y] <= k)
				{
					f[nx][ny]  = f[x][y];
					dir[nx][ny] = i+1;
					dfs(nx,ny);
				}
			}
		}
	}
}
int main()
{
	int t , i, j;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &m, &n);
		for(i = 0; i < m;  ++i)
		scanf("%s", map[i]);
		scanf("%d%d%d%d%d", &k, &x1, &y1, &x2, &y2);
		//initial
		x1 -= 1;
		y1 -= 1;
		x2 -= 1;
		y2 -= 1;
		for(i = 0; i < m; ++i)
		for(j = 0; j < n; ++j)
		f[i][j] = 10010;
		f[y1][x1] = -1;
		dir[y1][x1] = 0;
		map[y1][x1] = '*';
		dfs(y1, x1);
		if((x1 == x2 && y1 == y2) || f[y2][x2] <= k )
			printf("yes\n");
		else
			printf("no\n");
	}
	return 0;
}


题意:给出一个迷宫,并且给出起点和终点,求起点到终点所需要的最小的转弯次数,并与题目给出的转弯次数相比较,小于等于的情况下输出yes,说明能够在有限的转弯次数内走到终点,否则输出no。

思路:常规的深搜会超时,需要用两个数组的空间来换取时间,即一个数组用来存储起点到当前点的的最小拐弯次数,另一个数组记录在该最小拐弯次数情况下该点来时的方向。所以在每移动一个位置时,即可以判断移动后该点是否拥有新的最小的拐弯次数,如果有,则以该点接着往其他方向搜索,如果没有,则这个方向不再遍历。以此类推,直至走完整个地图,则数组中保存的终点中的值即为最小的拐弯次数。

注意:起点的初始方向不能和四个方向相同,并且要将起点的拐弯次数设置为-1,即从起点出发无论从哪个方向出发,这个出发方向都不会被算进拐弯次数内。

你可能感兴趣的:(c)