Atcoder151 D-Maze Master 题解

该博客详细介绍了Atcoder151 D-Maze Master问题的解决方案,强调这是一道使用宽度优先搜索(BFS)的典型题目。博主分享了AC代码,并解释了如何通过枚举起点和终点,利用队列进行宽搜,以找到最长路径。

这是一道较为规整的BFS,代码有点长

Maze Master 题址
题目解释:就是有一个长为H,宽为W的二维表,全部都是’.‘或’#’。你任意从一个‘.’走到另一个’.’(不可以斜着),在所有的路中,最长的那条是多少?

宏观思路:在主函数中枚举每一组起、止点,记录下他们的行列坐标,以此来做宽搜。宽搜返回来的值,还要比一下max。
宽搜很好做,用queue队列就OK了

配合代码讲一下:

struct pos{  //结构体,行列号和步数(值)
	int x;    
	int y;
	int step;
};

pos make_pos(int a,int b,int c)
{
	pos ret;  //打包用的
	ret.x=a;
	ret.y=b;    
	ret.step=c;
	
	return ret;
}
	for(int i1=1;i1<=n;++i1) //枚举开头的行坐标
	  for(int j1=1;j1<=m;++j1)//枚举开头的列坐标
	  {
	  	if(a[i1][j1]=='#')//如果当前格子是#,那就继续枚举
	  	  continue;
	  	for(int i2=1;i2<=n;i2++) //枚举结尾的行坐标
	  	  for(int j2=1;j2<=m;j2++)//枚举结尾的列坐标
	  	  {
	  	  	if(a[i2][j2]=='#') 
	  	  	  continue;
	  	  	if(i1==i2&&j1==j2)//如果开头和结尾是同一个点,那么重来
	  	  	  continue;
	  	  	  
	  	  	  maxv=max(maxv,bfs(i1,j1,i2,j2));
		   }
	   } 
int bfs(int sx,int sy,int ex,int ey)
// sx=start.x 起始点的行坐标  sy=start.y 起始点的列坐标 ex ey 同理

定义一个布尔型的vis[]数组,用来判重 false表示没来过,可以过来;true表示已来过,不能再来

while(!q.empty())
	{
		pos fr=q.front();//拿出队首
		q.pop();//队首出队
		if(fr.x==ex&&fr.y==ey)//如果当前的行列坐标,和结尾的坐标一样,说明已经结束
		 return fr.step;//返回值
		for(int i=0;i<4;i++)//位移增量,无需解释
		{
			int nx=fr.x+dx[i];
			int ny=fr.y+dy[i];
			if(vis[nx][ny])//如果已经来过这个点,就重新探索
			 continue;
			vis[nx][ny]=true;//如果没来过这个点,那就来一下,把他设成true
			
			pos newpo=make_pos(nx,ny,fr.step+1);//打包一下,记录行列号和值
			q.push(newpo);//入队
		}

下面贴一下AC代码:

#include <bits/stdc++.h>
using namespace std;

char a[22][22]; //行列放大两个,防止出圈

int n,m;
struct pos{
	int x;
	int y;
	int step;
};

pos make_pos(int a,int b,int c)
{
	pos ret;
	ret.x=a;
	ret.y=b;
	ret.step=c;
	
	return ret;
}

int bfs(int sx,int sy,int ex,int ey)
{
	bool vis[n+2][m+2];
	
	for(int i=0;i<=n+1;i++)
	  for(int j=0;j<=m+1;j++)
	    if(a[i][j]=='#')      //把墙壁‘#’,设为true表示不能来
	      vis[i][j]=true;
	    else vis[i][j]=false;
	    
	queue<pos> q;
	q.push(make_pos(sx,sy,0));//起点的行列号先入队
	vis[sx][sy]=true;//起点设成已来过
	
	int dx[4]={0,0,1,-1};
	int dy[4]={1,-1,0,0};
	
	while(!q.empty())
	{
		pos fr=q.front();
		q.pop();
		if(fr.x==ex&&fr.y==ey)
		 return fr.step;
		for(int i=0;i<4;i++)
		{
			int nx=fr.x+dx[i];
			int ny=fr.y+dy[i];
			if(vis[nx][ny])
			 continue;
			vis[nx][ny]=true;
			
			pos newpo=make_pos(nx,ny,fr.step+1);
			q.push(newpo);
		}
	}
	
}
int main()
{
	for(int i=0;i<22;i++)
	  for(int j=0;j<22;j++)
	    a[i][j]='#';
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	   cin>>a[i][j];
	   
	int maxv=0;
	for(int i1=1;i1<=n;++i1)
	  for(int j1=1;j1<=m;++j1)
	  {
	  	if(a[i1][j1]=='#')
	  	  continue;
	  	for(int i2=1;i2<=n;i2++)
	  	  for(int j2=1;j2<=m;j2++)
	  	  {
	  	  	if(a[i2][j2]=='#')
	  	  	  continue;
	  	  	if(i1==i2&&j1==j2)
	  	  	  continue;
	  	  	  
	  	  	  maxv=max(maxv,bfs(i1,j1,i2,j2));
		   }
	   } 
	   cout<<maxv<<endl;
	   return 0;
	   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值