HDU1728 逃离迷宫 DFS

逃离迷宫

Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status

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, x 1, y 1, x 2, y 2 (1 ≤ k ≤ 10, 1 ≤ x 1, x 2 ≤ n, 1 ≤ y 1,
2 ≤ m),其中k表示gloria最多能转的弯数,(x 1, y 1), (x 2, y 2)表示两个位置,其中x 1,x 2对应列,y 1, 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 

这个题卡在不知道怎么判是否转弯,不过看了大神的解题就懂了,程序里的(dir!=-1 && i!=dir)就是用来判断是否转弯了。

本题我是用的dfs,找到终点时并不晕就返回真,程序并没有遍历整个图。并且在走重时会根据在重点的转弯值turn判断以选优,

这在程序中已实现,并作为剪枝,注意本题剪枝很重要,不然会超时的!!

下面来解释一下bfs()中if()剪枝中为什么相等的情况不能剪掉(先看代码去):

如图:

很明显,如果k=1的话,那么途中红线是不符合题意的,我们来谈论最中心的那个点(下面我们叫它中心点):

走红线时,在中心点的turn值是1,当然要去终点的到还需要再转一次,就不符合题意,一次放弃这条路线,但是中心点的turn就此存在了,并且是1.

当再走蓝线时,走到该点时turn值也是1,此时人没晕,一直走是可以走到终点的,所以这种情况是应该输出“yes”的。

但如果你把相等的情况剪掉了,那么就是相当于把蓝线这种可能给否定了,那自然就错了。

造成这种情况的原因其实很简单,因为不同路线的到达相同的点时,因为来的时候方向不同,要是再朝相同的方向(即终点的方向)走时,有的需要转一次;有的则不需要,接着原来的方向走就行。

代码如下:

#include <stdio.h>
#include <string.h>
#include <math.h>
#define Max 999999
#include <algorithm>
using namespace std;

struct point
{
	int x,y;
}s[20000];

char map[110][110];
int turn[110][110];
int n,m,x2,y2,ok,k;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};

void dfs(int x,int y,int dir)
{
	int i,xx,yy;
	if(x==x2 && y==y2 && turn[x][y]<=k)		//成功的时候返回
	{
		ok=1;
		return ;
	}
	if(turn[x][y]>k)			//大于k时已晕,不行
		return ;

	if(x!=x2 && y!=y2 && turn[x][y]==k)			//如果(x,y)和终点(x2,y2),既不在同一行也不在同一列,那么要想到终点至少需要转一次,但现在已经转够k次了,故不行
		return ;
	for(i=0;i<4;i++)
	{
		xx=x+dx[i];
		yy=y+dy[i];
		if(xx<=0 || yy<=0 || xx>m || yy>n || map[xx][yy]=='*')
				continue;
//注意!!!下面这行中的turn[xx][yy]是表示(xx,yy)已经由别的路线走过了,并记录了turn[xx][yy],现在需要比较这次走到(xx,yy)和由别的路线走到
//(xx,yy)时,两个的turn值,如果上次的比这次的小,说明这次不行,故要continue;
		if(turn[xx][yy]<turn[x][y])		//这里相等的情况不能剪掉,原因开头已解释
			continue;
//下面这条if和上面的差不多,目的是:如果从(x,y)走一步到(xx,yy)需要转一次话,并且转过之后turn[x][y]+1依然比turn[xx][yy]大的话,也不符合
		if(dir!=-1 && i!=dir && turn[xx][yy]<turn[x][y]+1)
			continue;			//这两个if语句剪枝很重要,没有的话就超时
		if(dir!=-1 && i!=dir)
			turn[xx][yy]=turn[x][y]+1;
		else
			turn[xx][yy]=turn[x][y];
		map[xx][yy]='*';		//如果这里能走,就把这里变成不能走,然后再从这里开始递归,其实就是起到vis[][] 的作用,会用vis的话就不用追究了
		dfs(xx,yy,i);
		map[xx][yy]='.';		//这里再变成'.',是为了不影响其他的递归过程,因为其他路线可能还要从这里过
		if(ok)
			return ;
	}

}

int main()
{
	int i,j,t,x1,y1;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&m,&n);
		for(i=1;i<=m;i++)
			for(j=1;j<=n;j++)
				scanf(" %c",&map[i][j]);
		scanf("%d%d%d%d%d",&k,&y1,&x1,&y2,&x2);		//注意,这里是先接y,再接x,我被坑了好长时间
		memset(turn,Max,sizeof(turn));			//因为在dfs()中剪枝要去最小的转弯次数,所以turn要初始化成最大
		ok=0;
		turn[x1][y1]=0;
		dfs(x1,y1,-1);
		if(ok)
			printf("yes\n");
		else
			printf("no\n");
	}
	return 0;
}

另外需要注意的就是,scanf时,%c前面加个空格,即scanf(" %c",....),不然不行。

时间: 2024-10-24 15:02:54

HDU1728 逃离迷宫 DFS的相关文章

HDU1728 逃离迷宫 【方向BFS】

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 15120    Accepted Submission(s): 3650 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地

HDU 1728 逃离迷宫(DFS||BFS)

逃离迷宫 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去.令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的.我们假定给定的两个位置都是空地,初始时,gloria所面向的方向

HDU 1728 逃离迷宫(DFS经典题,比赛手残写废题)

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 27185    Accepted Submission(s): 6630 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方

HDU 1728 逃离迷宫 DFS+标记转弯数+优化

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16764    Accepted Submission(s): 4086 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地

HDU1728 逃离迷宫 【BFS】

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16840    Accepted Submission(s): 4108 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地

HDU1728 逃离迷宫【BFS】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1728 题目大意: 有一个M*N的矩阵迷宫.其中,字符'.'表示此处为空地,字符'*'表示此处为障碍.在迷宫中,只能向 相邻的上.下.左.右方向走.而且在走的时候,转弯最多不能超过k次.给你初始位置(x1,y1),终 止位置(x2,y2),问:是否能从初始位置走到终止位置. 思路: 建立一个结构体,结构体中(x,y)表示当前位置,t表示目前的转弯次数.搜索四个方向,并记录下转弯 数,如果转弯数大于或

hdu1728逃离迷宫 bfs

//bfs用vis[i][x][y][k] 表示从i的方向到x,y且剩下的转弯数是k #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 110 ; int vis[4][maxn][maxn][maxn] ; char map[maxn][maxn] ; struct node { int k

hdu1728 逃离迷宫bfs

题目链接:http://icpc.njust.edu.cn/Problem/Hdu/1728/ 关于广度优先搜索的第一篇题解.广度优先搜索,就是状态树的层次遍历,一层一层的搜索,直到搜索到目标状态为止.在扩展的过程中设定一种由上一层扩展到下一层的转化机制,将出现的新的状态放入队列之中,每次取出队首元素,大部分情况下bfs是用来搜索最优值的问题,优先队列的作用就是一旦搜索到目标状态,跟随的结果状态一定是最优的.为了避免重复相同的搜索,可设置访问记录.一般运用队列这种数据结构,使得最初搜索的状态在前

HDU 1728 逃离迷宫 单方向BFS 或者DFS加剪枝

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18519    Accepted Submission(s): 4463 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地