【JZOJ5793】小S练跑步【BFS】

题目大意:

题目链接:https://jzoj.net/senior/#main/show/5793
题目图片:
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fvx7ksrc55j30j20dw3z4.jpg
http://wx3.sinaimg.cn/mw690/0060lm7Tly1fvx7kss9v0j30jb0g1jro.jpg


思路:

P.S.本蒟蒻的语文不好,对于很难简化的题目起不到什么简化所用。各位dalao就看题目图片吧QWQ


正题:

很裸的广搜啊。。。
对于一个点,向四个方向搜,直到遇到不能走的位置在停下。
例如:
在这里插入图片描述
就往四个方向枚举,直到四个方向都走到底为止。
那么上图能走的(能转移的)被标记成红色就是:
在这里插入图片描述
这也就是和普通广搜的区别吧。。。

  • 普通广搜:每次往四个方向搜一个格子。
  • 这道题:每次往四个方向搜到不能搜为止。

其实很像最小拐弯问题吧。
还有,这道题的visvis数组也会有一个小变化。当我们搜到一个点(x,y)(x,y)vis[x][y]=truevis[x][y]=true时,不要立刻breakbreak,因为可能会遇到如下情况:
在这里插入图片描述
蓝色的块从绿色的块转移来,visvis已经被标记。
在这里插入图片描述
我们现在要从红色点往右搜,那么
在这里插入图片描述
当我们搜到(3,3)(3,3)时,如果直接退出,不继续往后搜,那么就会导致(3,4)(3,4)的本来应该搜到的格子无法搜到。
所以就应该直接跳过已被标记的格子,直接跳到下一个
在这里插入图片描述
注意终点(n,m)(n,m)也有可能是SS。但是这种情况还是算可以到达的。记得先将终点的SS去掉。


代码:

#include <cstdio>
#include <queue>
#include <ctime>
#include <cstring>
#include <iostream>
#define N 510
using namespace std;

const int dx[]={0,1,-1,0,0};
const int dy[]={0,0,0,1,-1};
const char way[]={' ','D','U','R','L'};  //四个方向
int n,m;
char c[N][N];
bool vis[N][N];

void bfs()
{
	queue<int> x;
	queue<int> y;
	queue<int> dis;
	vis[1][1]=1;
	x.push(1);
	y.push(1);
	dis.push(-1);
	while (x.size())
	{
		if (c[x.front()][y.front()]!='S')
		 for (int i=1;i<=4;i++)
		 {
			if (c[x.front()][y.front()]==way[i]) continue;
			int k=0;
			while (1)
			{
				k++;
				int xx=x.front()+k*dx[i];
				int yy=y.front()+k*dy[i];
				if (xx<1||yy<1||xx>n||yy>m) break;
				if (c[xx][yy]=='S') break;
				if (c[xx-dx[i]][yy-dy[i]]==way[i]) break;
				if (vis[xx][yy]) continue;
				vis[xx][yy]=1;
				x.push(xx);
				y.push(yy);
				dis.push(dis.front()+1);
				if (xx==n&&yy==m)
				{ 
					printf("%d",dis.front()+1);
					return;
				}
			}
		 }
		x.pop();
		y.pop();
		dis.pop();
	}
	printf("No Solution");
	return;
}		

int main()
{
	cin>>n>>m;
	if (n==1&&m==1) 
	{
		printf("0");
		return 0;
	}
	for (int i=1;i<=n;i++)
	 cin>>c[i]+1;
	c[n][m]=' ';
	bfs();
	return 0;
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998545.html