象棋马走日&&全球变暖&&乳草的入侵——(bfs经典例题)

目录

1.bfs马走日思路导图

2.bfs宽度搜索思想

3.主旨展现

4.例题(1)来喽——马走日(象棋遍历问题)

5.例题(2)来喽——全球变暖(icpc)

 6.例题(3)来喽——乳草的入侵——有坑小心有毒


1.bfs马走日思路导图

相信大家都了解象棋中马的走法,如图所示(在不考虑拌马蹄的情况下);

2.bfs宽度搜索思想

  • 与常规bfs相比,走象棋的主要不同点就是方向从4个变成了8个;
  • 其他的和bfs模板极其相似,如下所示。
  1. bfs它在搜索中并不理会目标在哪里,只会按照自己题目中给定的方向去朝向扩散;
  2. 因为要一层一层搜索,先进来的点先搜索,后进来的点后搜索,和队列的特征很符合,因此一般用队列进行解决;

3.主旨展现

  • 首先d[N][N]初始化为 - 1,然后d[x][y]入队,进行bfs循环,行走固定位置;
  • 然后用d[N][N]来储存能到走“车”的最短步数
  • 最后输出最小步数;

4.例题(1)来喽——马走日(象棋遍历问题)

题目描述


Raksasa非常喜欢下棋,同时充满好奇心。有一天在下棋的时候,Raksasa突然想到一个问题。
在一个n∗m的棋盘上,马处于棋盘上一个位置,車处于另外q个位置(所有棋子的位置均不相同)。假如这个車,爆胎了(不能移动)。马最少需要几步才能踩掉这个車,或者踩不到。
请你棒Raksasa想出这个问题的答案,如果能踩到,输出最少次数,否则输出"−1"。
本题将给出q次询问,马的位置恒定不变。

输入格式

第一行为三个整数n,m,q(1≤n,m≤1000)n表示棋盘的行数,m表示棋盘的列数,q表示询问次数。
第二行为两个整数x(1≤x≤n),y(1≤y≤m),x表示马所处的行数,y表示马所处的列数。
接下来的q行,每行为两个整数posx(1≤posx≤n)(1≤posy≤m)posx表示车所处的行数,posy表示车所处的列数。

输出格式

输出q行,每行输出一个整数,为最小查询次数或者-1;

样例输入

5 9 1
3 5
5 9

结果输出

2
#include<bits/stdc++.h>

using namespace std;

typedef pair<int, int>PII;//定义队列
queue<PII>q;
const int N = 1010;
int n, m, l;
int d[N][N];
int dx[8] = { -2,-2,-1,-1,1,1,2,2 };
int dy[8] = { 1,-1,2,-2,2,-2,1,-1 }; //8个位置

void bfs()
{

    while (q.size())
    {
        PII t = q.front();
        q.pop();
        int x = t.first, y = t.second;
        for (int i = 0; i < 8; i++)
        {
            int tx = x + dx[i];
            int ty = y + dy[i];
            if (d[tx][ty] != -1 || tx <= 0 || ty <= 0 || tx > n || ty > m) continue;
            else
            {
                d[tx][ty] = d[x][y] + 1;//步数加1
                q.push({ tx,ty });
            }
        }
    }
}
int main()
{
    cin >> n >> m >> l;
    int a, b;
    cin >> a >> b;
    memset(d, -1, sizeof d);//初始化为-1
    d[a][b] = 0;
    q.push({ a,b });
    bfs();
    while (l--)
    {
        int x, y;
        cin >> x >> y;
        cout << d[x][y] << endl;
    }
}

5.例题(2)来喽——全球变暖(icpc)

问题描述


你有一张某海域 N x N 像素的照片,. 表示海洋、# 表示陆地,如下所示:

. . . .  . . .
. # # . . . .
. # # . . . .
. . . . # # .
. . # # # # .
. . . # # # .
. . . . . . .

其中 “上下左右” 四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2 座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。

具体来说如果一块陆地像素与海洋相邻 (上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:
 

. . . . . . .
. . . . . . .
. . . . . . . 
. . . . . . .
. .  . . # . .
. . . . . . .
. . . . . . . 

输入格式
第一行包含一个整数 N,以下 N 行 N 列代表一张海域照片;

照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋;

输出格式
一个整数表示答案;

样例(1)输入:

7
. . . .  . . .
. # # . . . .
. # # . . . .
. . . . # # .
. . # # # # .
. . . # # # .
. . . . . . .

输出结果:

1

样例(2)输入:

11
...........
.##........
.##........
....##.#...
..#######..
...###.#...
...........
..#....#...
......###..
.......#...
...........

结果输出:

2
/*这题的思路:
1、我们先用flood fill去判断整块地图中有多少不同的连通块,也就是有不同的岛屿
2、当我们在进行判断这块岛屿的时候,如果这块岛屿的所'#'的数目==与海洋相邻''#的数目的时候,
   这块陆地就一定会沉没ans++,否则就一定不会沉没.
*/

#include<iostream>//Flood fil——去找地图里面有多少不同的联通块然后在里面进行条件的判断
#include<algorithm>
#include<cstring>//有个坑,自己跳坑里面去了,唉!!memset加错了,唉,找半天bug,真菜
#include<queue>

using namespace std;
typedef pair<int, int>PII;

const int N = 1e3 + 10;
int n, d[N][N], ans;
char g[N][N];
int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };

void bfs(int a, int b, int& sum1, int& sum2)
{
	queue<PII>q;
	q.push({ a,b });
	//memset(d, 0, sizeof(d));不能加,如果加上就会破坏之前处理好的条件!!!!!!!
	d[a][b] = 1;
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		sum1++;
		int flag = 0;
		for (int i = 0; i < 4; i++)
		{
			int x = t.first + dx[i], y = t.second + dy[i];

			if (x >= 0 && y >= 0 && x < n && y < n && d[x][y] == 0 && g[x][y] == '.')   flag = 1;
			if (x >= 0 && y >= 0 && x < n && y < n && d[x][y] == 0 && g[x][y] == '#')
			{
				q.push({ x,y });
				d[x][y] = 1;
			}
		}
		if (flag == 1) sum2++;
	}
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> g[i][j];
		}
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (d[i][j] == 0 && g[i][j] == '#')
			{
				//sum1是某块岛屿中的所有'#'的数目
				//sum2是某块岛屿中的所有与海洋相邻的'#'的数目
				int sum1 = 0, sum2 = 0;
				bfs(i, j, sum1, sum2);
				if (sum1 == sum2) ans++;
			}
		}
	}
	cout << ans << endl;
	return 0;
}

 6.例题(3)来喽——乳草的入侵——有坑小心有毒

题目描述

农民约翰一直努力让他的草地充满鲜美多汁而又健康的牧草,可惜天不从人愿,他在植物大战人类中败下阵来,邪恶的乳草已经在他的农场的西北部份占领了一片立足之地,草地像往常一样,被分割成一个高度为 Y,宽度为 X 的直角网格。

(1,1) 是左下角的格(也就是说坐标排布跟一般的 X,Y 坐标相同)。乳草一开始占领了格 (Mx,My)。每个星期,乳草传播到已被乳草占领的格子四面八方的每一个没有很多石头的格(包括垂直与水平相邻的和对角线上相邻的格)内。1 周之后,这些新占领的格又可以把乳草传播到更多的格里面了。达达想要在草地被乳草完全占领之前尽可能的享用所有的牧草。

她很好奇到底乳草要多久才能占领整个草地。

如果乳草在 0 时刻处于格 (Mx,My),那么几个星期以后它们可以完全占领入侵整片草地呢(对给定的数据总是会发生)?在草地地图中,. 表示草,而 * 表示大石。比如这个X=4,Y=3 的例子。

....
..*.
.**.


如果乳草一开始在左下角(第 1 排,第 1 列),那么草地的地图将会以如下态势发展:

        ....  ....  MMM.  MMMM  MMMM  
        ..*.  MM*.  MM*.  MM*M  MM*M  
        M**.  M**.  M**.  M**.  M**M  
星期数    0     1     2     3     4



乳草会在 4 星期后占领整片土地。

输入格式
第 1 行: 四个由空格隔开的整数: X, Y, Mx, My
第 2 到第 Y+1 行: 每行包含一个由 X 个字符(. 表示草地,* 表示大石)构成的字符串,共同描绘了草地的完整地图。

输出格式
输出一个整数,表示乳草完全占领草地所需要的星期数。

数据范围
1≤X,Y≤100


输入样例:

4 3 1 1
....
..*.
.**.


输出样例:
 

4

#include<iostream>//输入开始坐标的时候有毒
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;
typedef pair<int, int>PII;

const int N = 110;
int dx[8] = { -1,-1,-1,0,0,1,1,1 };
int dy[8] = { -1,0,1,1,-1,-1,0,1 };
int n, m, a, b, res, d[N][N];
char g[N][N];

int bfs(int a, int b)
{
	queue<PII>q;
	q.push({ a,b });
	memset(d, -1, sizeof(d));
	d[a][b] = 0;
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		for (int i = 0; i < 8; i++)
		{
			int x = t.first + dx[i], y = t.second + dy[i];
			if (x >= 0 && y >= 0 && x < m && y < n && d[x][y] == -1 && g[x][y] == '.')
			{
				d[x][y] = d[t.first][t.second] + 1;
				q.push({ x,y });
				res = max(res, d[x][y]);//需要判断一下,因为不知道哪个点是最后一个点
			}
		}
	}
	return res;
}

int main()
{
	cin >> n >> m >> a >> b;
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> g[i][j];
		}
	}
	cout << bfs(m - b, a - 1) << endl;//就在这输入开始坐标的时候有毒
	return 0;
}

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大小胖虎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值