I - 逃离迷宫 HDU - 1728 (bfs)

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

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

-------------------------------------------------------------------------------------

题意大约就是一道迷宫,起点到终点,现在不是限制步数,而是限制转弯次数。第一次可以任意选择一个方向出发,不消耗转弯次数,问最终是否能走到。

------------------------------------------------------------------------------------------------

一开始以为只要在结构体中加一个变量记录方向变化就可以了,照着模板bfs,wa了2遍,始终想不出哪里错了。后来去看了题解,明白了别人的思路。和自己的想法进行比较。最终找到了bug。

bfs会把所有点访问过以后记录到队列中,之后都不再访问,因为在原版bfs中,每一个点,在第一次被走到时,一定是最近的情况,所以之后都不需要再走,以为之后再走到这个点时的步数一定大于等于第一次走到的步数,因此有了vis这个数组,记录是否访问过这个节点。

这题我想的还是bfs原版,但是,仔细思考会发现,走到一个点,也许步数一样,并且第一次步数做最小,但是转弯次数并不是第一次走到的就是最少的。与dis【4】【2】定义的方向,还有地图都有关系。也想了把vis去掉,每个点都走一下,比较k,马上被自己否决了,肯定会爆。最终还是没想出怎么用"记录方向向量"这种想法来A这题。

--------------------------------------------------------------------------------------------

WA版

#include<deque>
#include<queue>  
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<stack>
#include <string>
#include<set>
const int inf = 0x3f3f3f3f;
const int maxn = 10e5+7;
using namespace std;
char map[110][110];
int n,m;
struct point
{
	int x;
	int y;//横纵坐标
	int way;//到这个点的方向
	int k;//转弯次数
	char q;
}st,en;
int vis[110][110]={0};

int k;
void bfs()
{
	int dis[4][2]={0,-1,0,1,1,0,-1,0};
	queue<point>que;
	st.k=-1;//第一个点的转弯次数设为-1
	st.way=4;//第一个点的方向为4,与上下左右任何一个方向都不同,认为第一次选择方向就是一次转向
	que.push(st);
	vis[st.y][st.x]=1;
	while(!que.empty())
	{
		point now=que.front();
		que.pop();
		point next;
		if(now.y==en.y&&now.x==en.x&&now.k<=k)
		{
			printf("YES\n");
			return ;
		}
		for(int i=0;i<4;i++)
		{
			next.x=now.x+dis[i][0];
			next.y=now.y+dis[i][1];
			next.way=i;//i就是方向
			if(next.x>0&&next.x<=n&&next.y>0&&next.y<=m&&!vis[next.y][next.x]&&map[next.y][next.x]!='*')
			{
				if(next.way!=now.way)
				    next.k=now.k+1;
                else
                    next.k=now.k;
				que.push(next);
				vis[next.y][next.x]=1;
				
			}
		}
	}
	printf("NO\n");
	return ;
}

void init()
{
	memset(map,0,sizeof(map));
	memset(vis,0,sizeof(vis));
}

int main()
{
	int t;
	cin>>t;
	while(t--){
		init();
		cin>>m>>n;
		getchar();
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=n;j++)
			{
				cin>>map[i][j];
			}
		}
		//for(int i=1;i<=m;i++)
		//{
			//for(int j=1;j<=n;j++)
			//{
				//cout<<map[i][j];
			//}
			//printf("\n");
	//	}
		int x,y,x2,y2;
		cin>>k>>x>>y>>x2>>y2;
		st.y=y,st.x=x;
		en.y=y2,en.x=x;
		bfs();
	}
	return 0;
}

----------------------------------------------------------------------------------------------------------

AC版

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<utility>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<functional>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
const int maxn = 110;
int n, m, k, flag;
bool vis[maxn][maxn];
char mmp[maxn][maxn];
int dx[4] = { 0,0,-1,1 }, dy[4] = { 1,-1,0,0 };
struct node
{
	int x, y, k;
}st, en;
void bfs(node st, node en)
{
	queue<node> q;
	st.k = -1;
	q.push(st);
	vis[st.x][st.y] = true;
	while (!q.empty())
	{
		node u, v;
		u = q.front();
		q.pop();
		if (u.x == en.x&&u.y == en.y&&u.k <= k)
		{
			flag = 1;
			break;
		}
		v.k = u.k + 1;
		for (int i = 0;i < 4;i++)
		{
			int nextx = u.x + dx[i], nexty = u.y + dy[i];
			while (nextx > 0 && nextx <= m&&nexty > 0 && nexty <= n && mmp[nextx][nexty] == '.')
			{
				if (!vis[nextx][nexty])
				{
					vis[nextx][nexty] = true;
					v.x = nextx, v.y = nexty;
					q.push(v);
				}
				nextx += dx[i], nexty += dy[i];
			}
		}
	}
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> m >> n;
		flag = 0;
		for (int i = 1;i <= m;i++)
			for (int j = 1;j <= n;j++)
				cin >> mmp[i][j];
		cin >> k >> st.y >> st.x >> en.y >> en.x;
		memset(vis, false, sizeof(vis));
		bfs(st, en);
		if (flag)
			cout << "yes" << endl;
		else
			cout << "no" << endl;
	}
	
	return 0;
}

在确定一个方向后,就把这个方向的所有点走完,以为这样的话,k是相同的,并且这样bfs,每一个点第一次到的时候,必定是转弯次数最少的时候,便可以记录下来,之后无需在访问。

----------------------------------------------------------------------------------------------

给出一组简单数组,可以体会区别。

3 3

. . .

. . .

* . .

1 1 1 2 3

假设搜索顺序是 下 上 右 左。第一个搜到终点的路径是 (1,1)->(1,2)->(2,2)->(2,3),k=2>1;

但是其实(1,1)->(2,1)->(2,2)->(2,3),k=1;

猜你喜欢

转载自blog.csdn.net/qq_41539869/article/details/81191800