给定一个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;