NYOJ1129-很新颖的DFS

1.题目描述:

Salvation

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述

     

    神秘瀑布镇是一个神秘的地方,那里有吸血鬼,狼人,巫师,二重身。 Klaus(吸血鬼祖先) 为了利用 Elena 的血液发展他的混血大军(吸血鬼&狼人),也来到了神秘瀑布镇。Stefan 因为深爱着 Elena ,于是 Stefan 决定去唤醒吸血鬼猎人,来解救 Elena 

     吸血鬼猎人被封锁在一个迷宫里,这个迷宫有一种特性,只要进入就会失去方向感。于是 Stefan 想到一种方法,以左为标准(即优先左走),其次向前,向右,如果都无法走就向后走(即向右转两次)。他可以向上下左右四个方向的空格移动一个格,每次耗费1分钟。Stefan 在得知你是一个有天赋的程序员后,决定让你判断他是否能找到吸血鬼猎人。

输入
输入包含多组测试数据,第一行输入 n , m ( 2 < n ,m <= 100) ,接下来n行每行m个字符,第 n + 2 行一个字符表示初始方向(E W S N)。
“.”代表空格 ,“#”代表墙 , “ T ”代表初始位置,“X”代表吸血鬼猎人的位置。
输出
输出一行,如果能找到输出“YES”,否则输出“NO”。
样例输入
4 4
....
.##.
.##.
TX..
N
4 4
....
.##.
.###
T#.X
N
样例输出
YES
NO
提示
优先左走即:如果左边能走就向左走,如果不能走向前走,如果前不能走,向右走,如果右不能走向后走。

2.算法思想:

首先本体很明显需要用到DFS来查找可行解,但是本体新颖之处有两个
1.变方向
2.顺路径搜索
我们先来看看顺路径搜索的策略:
首先,根据我们以往的DFS的经验来看,我们想要查找可行解的话,需要的是将整个图进行遍历,用深搜的话是O(n*2)的时间复杂度,但是本体的特殊性在于我们是有方向优先的,所以说,我们不能按照以往的思维习惯来在每个点的基础上搜四个方向
相反,我们应该按照我们平常找路的思路来
其实我们平常找路的思路和标准的DFS的回溯思想还好i有着不一样的地方的
在理清题意之前,我们首先需要搞明白两者之间的不同之处

回溯的思想:利用递归,我们每次的四个方向查找失败之后,都会回溯至父点处重新进行下一轮选择
本题的思路:因为本题中声明了我们的搜索方式是按照左-前-右-后的思路来进行查找,所以说,加入我们走进了死胡同,三个方向都查找失败,但是轮到我们要往回走,往回走的时候,方向就改变了,在回溯法的思想中,我们遇到死胡同之后,因为向后的方向已经被标记过走过,所以说,我们是直接回溯至源点做下一轮选择,这两点是不一样的

就跟本来说,其实我们只要将平常的DFS的搜索时不要进行标记,允许我们向后走原路的话,也可以轻而易举结局这个小的问题


其次,变方向,照理来说,变方向是非常的复杂的,我开始的思路是开辟四种选择策略,针对不同的方向选择不同的选择策略,但是发现没有领悟精髓
大神的公式键值精简到世界崩塌,还没有搞懂原理,但是参考一下吧

3.AC代码

1.大神的简化代码:

#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"
#define N 120

using namespace std;

int nx[4]={-1,0,1,0};
int ny[4]={0,-1,0,1};
int n,m;
int book[N][N];
char map[N][N];
int bx,by;
int j;
char d;
int ds;

void dfs(int x,int y,int p)
{
	if(j) return ;
	for(int i=1;i>-3;i--)
	{
		int k=(p+i+8)%4;
		int dx=x+nx[k];
		int dy=y+ny[k];
		if(dx<1||dy<1||dx>n||dy>m||map[dx][dy]=='#') continue;
		else
		{
			if(map[dx][dy]=='X')
			{
				j=1;
				return ;
			}
			else
			{
				if(book[dx][dy]==4) return ;
				book[dx][dy]++;
				dfs(dx,dy,k);
				return ; 
			}
		}
	}
} 

int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		j=0;
		memset(book,0,sizeof(book));
		memset(map,0,sizeof(map));
		getchar();
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				scanf("%c",&map[i][j]);
				if(map[i][j]=='T')
				{
					bx=i;
					by=j;
				} 
			}
			getchar();
		}
		scanf("%c",&d);getchar();
		if(d=='N') ds=0;  
        else if(d=='W') ds=1;  
        else if(d=='S') ds=2;  
        else ds=3;
		dfs(bx,by,ds);
		if(j) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

2.我的思路:

#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"

using namespace std;

int n,m;
int nn[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
int ns[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int nw[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
int ne[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
char map[200][200];
int book[200][200];
char dir;
int bx,by;
int ex,ey;

bool dfs(int x,int y,char d)
{
	if(d=='N')
	{
		int dx,dy;
		for(int i=0;i<4;i++)
		{
			dx=x+nn[i][0];
			dy=y+nn[i][1];
			if(book[dx][dy]==4) return false;
			if(dx==ex&&dy==ey) return true;
			book[dx][dy]++;
			if(dx<1||dy<1||dx>n||dy>m||map[dx][dy]=='#') continue;
			else
			{
				bool k;
				switch(i)
				{
					case 0:k=dfs(dx,dy,'W');break;
					case 1:k=dfs(dx,dy,'N');break;
					case 2:k=dfs(dx,dy,'E');break;
					case 3:k=dfs(dx,dy,'S');break;
				}
				if(k==true) return true;
			    else return false;
			}
		}
	}
	else if(d=='S')
	{
		int dx,dy;
		for(int i=0;i<4;i++)
		{
			dx=x+ns[i][0];
			dy=y+ns[i][1];
			if(book[dx][dy]==4) return false;
			if(dx==ex&&dy==ey) return true;
			book[dx][dy]++;
			if(dx<1||dy<1||dx>n||dy>m||map[dx][dy]=='#') continue;
			else
			{
				bool k;
				switch(i)
				{
					case 0:k=dfs(dx,dy,'E');break;
					case 1:k=dfs(dx,dy,'S');break;
					case 2:k=dfs(dx,dy,'W');break;
					case 3:k=dfs(dx,dy,'N');break;
				}
				if(k==true) return true;
				else return false;
			}
		}
	}
	else if(d=='E')
	{
		int dx,dy;
		for(int i=0;i<4;i++)
		{
			dx=x+ne[i][0];
			dy=y+ne[i][1];
			if(book[dx][dy]==4) return false;
			if(dx==ex&&dy==ey) return true;
			book[dx][dy]++;
			if(dx<1||dy<1||dx>n||dy>m||map[dx][dy]=='#') continue;
			else
			{
				bool k;
				switch(i)
				{
					case 0:k=dfs(dx,dy,'N');break;
					case 1:k=dfs(dx,dy,'E');break;
					case 2:k=dfs(dx,dy,'S');break;
					case 3:k=dfs(dx,dy,'W');break;
				}
				if(k==true) return true;
				else return false;
			}
		}
	}
	else if(d=='W')
	{
		int dx;
		int dy;
		for(int i=0;i<4;i++)
		{
			dx=x+nw[i][0];
			dy=y+nw[i][1];
			if(book[dx][dy]==4) return false;
			if(dx==ex&&dy==ey) return true;
			book[dx][dy]++;
			if(dx<1||dy<1||dx>n||dy>m||map[dx][dy]=='#') continue;
			else
			{
				bool k;
				switch(i)
				{
					case 0:k=dfs(dx,dy,'S');break;
					case 1:k=dfs(dx,dy,'W');break;
					case 2:k=dfs(dx,dy,'N');break;
					case 3:k=dfs(dx,dy,'E');break;
				}
				if(k==true) return true;
				else return false;
			}
		}
	}
}

int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(book,0,sizeof(book));
		getchar();
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				scanf("%c",&map[i][j]);
				if(map[i][j]=='T')
				{
					bx=i;
					by=j;
				}
				if(map[i][j]=='X')
				{
					ex=i;
					ey=j;
				}
			}
			getchar();
		}
		scanf("%c",&dir);
		getchar();
		if(dfs(bx,by,dir)) printf("YES\n");
		else printf("NO\n"); 
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值