【洛谷P2199】最后的迷宫【BFS】【DFS】

题目大意:

题目链接:https://www.luogu.org/problemnew/show/P2199
给出一个图及起点和终点,只要到达终点所在行、列或对角线上且两点之间没有墙就算到达终点。求到达终点的最少步数。


思路:

这道题真的算是蓝题吗。。。
算是很裸的广搜了。
这道题和裸的广搜其实只有一个差别:只要到达终点所在行、列或对角线上且两点之间没有墙就算到达终点。也就是说,这道题有多个终点,到达任意一个即可。
那么就直接跑一边DFS,从原终点往8个方向跑,直到遇见墙为止。那么走到的点就都是成立的终点。
之后就从起点跑BFS。就完全是裸的了。
还有这道题说100%100\%的数据范围是n×m16384n\times m\leq 16384,所以如果是最坏情况就会有n=1,m=16384n=1,m=16384,那么开二维数组就会炸内存。所以要把二维数组压成一个一位数组。
有多组数据,所以时间复杂度为O(tnm)O(tnm)


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int dx[]={0,1,-1,0,0,-1,-1,1,1};
const int dy[]={0,0,0,1,-1,-1,1,-1,1};
int n,m,sx,sy,tx,ty,head,tail,ans[20501],state[20501];
bool a[20501],map[20501],p[20501];
char c;

void dfs(int x,int y,int k)  //找终点
{
	if (map[(x-1)*m+y]==1) return;  //墙
	if (x<1||x>n||y<1||y>m) return;  //越界
	a[(x-1)*m+y]=1;  //标记为终点
	dfs(x+dx[k],y+dy[k],k);
}

void bfs()  //裸的广搜
{
	head=0;
	tail=1;
	state[1]=(sx-1)*m+sy;
	while (head<tail)
	{
		head++;
		for (int i=1;i<=4;i++)
		{
			tail++;
			int x=(state[head]-1)/m+1;  
			int y=state[head]-(x-1)*m;  //取出行和列
			x+=dx[i];
			y+=dy[i];  //移动
			if (x<1||x>n||y<1||y>m)  //越界
			{
				tail--;
				continue;
			}
			state[tail]=(x-1)*m+y;  //入队
			if (p[state[tail]]||map[state[tail]])   //来到过这个点或是墙
			{
				tail--;
				continue;
			}
			p[state[tail]]=1;
			ans[tail]=ans[head]+1;
			if (a[state[tail]])  //到达任意一个终点
			{
				printf("%d\n",ans[tail]);
				return;
			}
		}
	}
	printf("Poor Harry\n");  //无法到达
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=m;j++)
	 {
		cin>>c;
		while (c=='\n'||c==' ') cin>>c;
		if (c=='X') map[(i-1)*m+j]=1;
	 } 
	while (1)
	{
		scanf("%d%d%d%d",&tx,&ty,&sx,&sy);
		if (!tx&&!ty&&!sx&&!sy) break;
		memset(a,0,sizeof(a));
		memset(ans,0,sizeof(ans));
		memset(p,0,sizeof(p));
		a[(tx-1)*m+ty]=1;
		for (int i=1;i<=8;i++)
		 dfs(tx,ty,i);
		if (a[(sx-1)*n+sy])   //特判,本来就在终点上
		{
			printf("0\n");
			continue;
		}
		bfs();
	}
	return 0;
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998601.html