初学 bfs 以及简单习题练习

7 篇文章 0 订阅
2 篇文章 0 订阅

bfs

参加过一些ac的竞赛了,一直搞不清楚bfs,数据结构方面对队列的知识也大多了解,但是一直对bfs不怎么感冒,这两天看了很多文章终于有点懂了- -

大致模板

1.定义地图数组mp[]以及其对应的visit数组vis[]
2.定义结构体 存放坐标以及步数信息
3.定义移动数组 
5.bfs(起点、终点)
{
          queue<**> q;  创建队列
          起点进队列 q.push(起点)
          更新vis数组
          定义结构体对象t,承载队头
          队头出队
          while(!empty())
          {
                   ①if(到达终点?)   return  t.步数;  在这不用+1
                   for(i=0;i<4;i++){
                   ②if(到达终点?)   return  t.步数+1;此步骤与①处等效
                   if(判断位置合法?)  continue;
                   结构体对象t1承载新坐标属性(xy step要+1 )
                   t1入队
                   }
          }
          return -1;遍历完后依然没到终点
}

题目1

这是一个关于二维迷宫的题目。我们要从迷宫的起点 ‘S’ 走到终点 ‘E’,每一步我们只能选择上下左右四个方向中的一个前进一格。 ‘W’ 代表墙壁,是不能进入的位置,除了墙壁以外的地方都可以走。迷宫内的 ‘D’ 代表一道上锁的门,只有在持有钥匙的时候才能进入。而 ‘K’ 则代表了钥匙,只要进入这一格,就会自动地拿到钥匙。最后 ‘.’ 则是代表空无一物的地方,欢迎自在的游荡。

本题的迷宫中,起点、终点、门跟钥匙这四个特殊物件,每一个恰好会出现一次。而且,此迷宫的四周 (最上面的一行、最下面的一行、最左边的一列以及最右边的一列) 都会是墙壁。

请问,从起点到终点,最少要走几步呢?

输入描述

输入的第一行有两个正整数H, W,分别代表迷宫的长跟宽。
接下来的H行代表迷宫,每行有一个长度恰为W的字串,此字串只包含'S', 'E', 'W', 'D ', 'K', '.'这几种字元。

输出描述

请在一行中输出一个整数代表答案,如果无法从起点走到终点,请输出-1。

示例

输入

4 12
WWWWWWWWWWWW
WE.W.S..W.KW
W..D..W....W
WWWWWWWWWWWW

输出
20
输入

6 6
WWWWWW
WEWS.W
W.WK.W
W.WD.W
W.W..W
WWWWWW

输出
-1

题目1代码


#include<bits/stdc++.h>
using namespace std;
char mp[500][500];  //注意地图数组不能叫map map是关键字c++会报错
int vis[500][500];
int h, w;  //长和宽 其实对应着行列
int dx[] = { 1,-1,0,0 };  //右左下上
int dy[] = { 0,0,1,-1 };
struct ren
{
	int x;
	int y;
	int step = 0;
}st,ed,key,door;  //start  end  key钥匙 door 门
int bfs(ren beg, ren end)
{
	queue<ren> q;
	q.push(beg);
	vis[beg.x][beg.y] = 1;
	while (!q.empty())
	{
		ren temp, t;
		temp = q.front();
		q.pop();
		//if (temp.x == end.x && temp.y == end.y) return temp.step;
		for (int i = 0; i < 4; i++)
		{
			
			int xx = temp.x + dx[i];
			int yy = temp.y + dy[i];
			t = temp;        
			if (xx == end.x && yy == end.y) return temp.step+1;
			if (xx < 0 || yy < 0 || xx >= h || yy >= w)//越界
				continue;
			if (vis[xx][yy] || mp[xx][yy] == 'D' || mp[xx][yy] == 'W') //走过或者是这个位置是门或者墙
				continue;

			
			t.x = xx;
			t.y = yy;
			t.step++; //更新新的节点
			q.push(t);  //入队
			vis[xx][yy] = 1;
		}
	}
	return -1;
}
int main()
{
	cin >> h >> w;
	for (int i = 0; i < h; i++)  //录入地图
	{
		for (int j = 0; j < w; j++)
		{
			cin >> mp[i][j];
			if (mp[i][j] == 'S') st.x = i, st.y = j;
			if (mp[i][j] == 'E') ed.x = i, ed.y = j;
			if (mp[i][j] == 'K') key.x = i, key.y = j;
			if (mp[i][j] == 'D') door.x = i, door.y = j;
		}
	}
	//不走钥匙
	memset(vis, 0, sizeof(vis));
	int ans1 = bfs(st, ed);
	//找钥匙
	memset(vis, 0, sizeof(vis));
	int  ans2 = bfs(st, key);
	mp[door.x][door.y] = '.';
	//钥匙找门
	
	memset(vis, 0, sizeof(vis));
	int  ans3 = bfs(key, door);
	//men找出口
	memset(vis, 0, sizeof(vis));
	int  ans4 = bfs(door, ed);
	if (ans1 == -1)   //直接走不成功
	{
		if (ans2 == -1 || ans3 == -1 || ans4 == -1)  //迂回路线也不成功
		{
			cout << "-1" << endl;
		}
		else
		{
			cout << ans2 + ans3 + ans4<<endl;
		}
	}
	else {//都可以走出来,就看哪个步数更少
		cout << min(ans1, ans2 + ans3 + ans4)<<endl;
	}
	return 0;
}

题目二

有一个n ×m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步

输入要求

一行四个数据,棋盘的大小和马的坐标

输出要求

一个n×m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)

示例

输入

3 3 1 1

输出

0    3    2    
3    -1   1    
2    1    4    

老规矩,搞各种数组,搞队列,然后开始排列

#include<bits/stdc++.h>
using namespace std;
const int maxn = 500;
int m, n,sx,sy;//地图
//直往下和往右走
int stp[maxn][maxn];


int dir[8][2] = { {1,2},{-1,2},{2,1},{-2,1},{2,-1},{-2,-1},{1,-2},{-1,-2}};//马可以走的八个方向 

struct pos { //坐标
	int x;
	int y;
	int step;
};
bool judge(int p, int q)
{
	if (p<1 || q<1 || p>m || q>n)
	{
		return false;
	}
	else if (stp[p][q] != -1)
	{
		return false;
	}
	else
		return true;
}
void bfs()
{
	queue<pos> que;
	pos temp1 = { sx,sy,0 };
	
	que.push(temp1);//jin dui
	stp[sx][sy] = 0;
	while (!que.empty()) { //队内元素为空
		pos f = que.front();
		que.pop();
		
		for (int i = 0; i < 8; i++)
		{   
			int dx = f.x + dir[i][0];
			int dy = f.y + dir[i][1];
			if (dx<1 || dy<1 || dx>m || dy>n) continue;
			if (stp[dx][dy] != -1)continue;
			pos temp = { dx,dy,f.step + 1 };
			//进队
			que.push(temp);
			//改进步数 
			stp[temp.x][temp.y] = temp.step;
			/*   下面注释的这些也可以 替换42-52行即可
			//走一步
			if (judge(f.x+dir[i][0], f.y + dir[i][1]))
			{   //建立新节点存储相关信息
				pos temp = { f.x + dir[i][0],f.y + dir[i][1],f.step + 1 };
				//进队
				que.push(temp);
				//改进步数 
				stp[temp.x][temp.y] = temp.step;	
			}
			*/
		}
	}
}
int main()
{
	cin >> m >> n>>sx>>sy;
	memset(stp, -1, sizeof(stp));

	//vis[sx][sy] = 1;
	bfs();
	//输出
	for (int i = 1; i <= m; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cout << stp[i][j];
			if (j != n) cout << " ";
		}
		cout << endl;
	}
}

题目三

二维矩阵,问从1,1位置到m,n位置有几条线路
ps:矩阵下标为双偶数的禁止路过,比如(2,2)、(4,4)等点
只能向右或者向下路行 .

输入要求

两个整数表示矩阵大小

输出要求

一个证书表示路线数量

示例

输入

3 4

输出

2
*
*
#include<bits/stdc++.h>
using namespace std;
int m, n;//地图
//直往下和往右走
int dir[2][2] = { {0,1},{1,0} };
int ans = 0;
struct pos { //坐标
	int x;
	int y;
};
void bfs()
{
	queue<pos> que;
	que.push({ 1, 1 });//jin dui
	while (!que.empty()) { //队内元素为空
		pos f = que.front();
		que.pop();
		for (int i = 0; i < 2; i++)
		{   //走一步
			int dx = f.x + dir[i][0];
			int dy = f.y + dir[i][1];
			//越界
			if (dx > m || dy > n) continue;
			//坐标规范
			if (dx % 2 == 0 && dy % 2 == 0) continue;
			//到达终点
			if (dx == m && dy == n) ans++;
			//入队
			que.push({ dx,dy });
		}
	}
}
int main()
{
	cin >> m >> n;
	bfs();
	cout << ans;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值