ssloj.1128.电子老鼠闯迷宫(BFS)

时间限制:1000MS 内存限制:256000KB

题目描述

如下图 12×12 方格图,找出一条自入口(2,9)到出口(11,8)的最短路径。

输入

第一行为一个数 n(2<=n<=12),表示迷宫大小。
第二行为 4 个数,表示起点和终点。
第三起为 n∗n 的矩阵,0 表示通路,1 表示障碍。

输出

第一行为路径(格式见样例)
第二行为总的步数。(数据保证一定有解)

输入样例 
12 
2 9 11 8 
1 1 1 1 1 1 1 1 1 1 1 1 
1 0 0 0 0 0 0 1 0 1 1 1
1 0 1 0 1 1 0 0 0 0 0 1
1 0 1 0 1 1 0 1 1 1 0 1
1 0 1 0 0 0 0 0 1 0 0 1
1 0 1 1 1 1 1 1 1 1 1 1
1 0 0 0 1 0 1 0 0 0 0 1
1 0 1 1 1 0 0 0 1 1 1 1
1 0 0 0 0 0 1 0 0 0 0 1
1 1 1 0 1 1 1 1 0 1 0 1
1 1 1 1 1 1 1 0 0 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1

第一眼看到这题有两种想法

1.dfs

从起点向4个方向搜索,用一个数组记录路径,搜到终点时用ans记录下步数,return回去继续递归,如果bs>=ans就返回(剪枝),直到找到答案。

那么用dfs行不行呢?

分析一下:

地图最多到12*12,极端数据是一个12*12的地图,上面全是0,没有障碍,从1,1出发到12,12。

那递归层数将会及其庞大,因为每个点要向4个方向搜索。

而且输出路径较为难处理。

那我们来看一下第二种。

2.bfs

这道题要求输出最短路径,是bfs所擅长的。

同样是搜索最短路径,深搜是直接递归到最后一层,在返回上一层,这样搜当然完整,但效率极低,会产生许多不必要的搜索,浪费时间。

而广搜是层层递进,逐层寻找,找到即为最优解。

还有,这题有个BUG,就是搜索顺序必须是:{{1,0},{-1,0},{0,1},{0,-1}},在出现多个最短路径时,最优解为这种。

然后这题不仅要输出最短步数,还要把路径也输出来,所以还要记录到达的每个点的父节点,输出时反向深搜回去寻找父亲,所以建议手敲队列哟。

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

int n,xa,ya,xb,yb,a[15][15],b[150][4],fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int h=1,t=1,ans;
bool v[15][15];
int bfs()
{
	while(h<=t)
	{
		for(int i=0;i<=3;i++)
		{
			int xx=b[h][0]+fx[i][0],yy=b[h][1]+fx[i][1];
			if(xx<=n&&xx>=1&&yy<=n&&yy>=1&&!v[xx][yy]&&a[xx][yy]==0)
			{
				v[xx][yy]=true;
			    t++;
				b[t][0]=xx;
				b[t][1]=yy;
				b[t][2]=h;//记录父节点
				b[t][3]=b[h][3]+1;//步数
				if(b[t][0]==xb&&b[t][1]==yb)//找到终点了
				return ans=b[t][3];
			}
		}
		h++;
	}
}
void dfs(int p)
{
	if(p==0) return;//找回起点了,返回(只有起点的父亲是0)
	dfs(b[p][2]);//反向搜索父亲
	cout<<"("<<b[p][0]<<","<<b[p][1]<<")";
	if(p!=t) cout<<"->";
}
int main()
{
     cin>>n>>xa>>ya>>xb>>yb;
     for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
       cin>>a[i][j];
     b[1][0]=xa,b[1][1]=ya,b[1][2]=b[1][3]=0;//队列初始化
     v[xa][ya]=true;
	 bfs();
	 dfs(t);//从列的最后一位(答案)回去寻找父亲
	 cout<<endl;
     cout<<ans;
	 return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值