41.岛屿数量(第四期模拟笔试)(BFS练习题)

链接:卡码网KamaCoder

题目:

给定一个 m 行 n 列的二维地图,初始化每个单元格都是海洋,二维地图外也全是海洋。 

操作 addLand 会将单元格(col, row)变为陆地。

定义一系列相连的被海洋包围的陆地为岛屿,

横向相邻或者纵向相连的岛屿才算相连(斜着相邻的不算)。 

现有一系列的 addLand 操作,给出每次 addLand 操作后岛屿的个数。

样例:

输入
3
3
4
0 0
0 1
1 2
2 1

输出
1 1 2 3

思路:

        根据题意,我们是要找到 连通块有多少个,就是多少个岛屿。

由于数据范围较小,所以我们可以使用 BFS 搜索,每一次放生成大陆后直接暴力查找连通块输出即可,而 非法坐标的情况,我们可以直接忽略。

代码详解如下:

#include <iostream>
#include <queue>
#include <cstring>
#define endl '\n'
#define x first
#define y second
#define mk make_pair
#define YES puts("YES")
#define NO puts("NO")
#pragma GCC optimize(3,"Ofast","inline")
#define ___G std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
using namespace std;
const int N = 500;

using PII = pair<int,int>;

// 控制查找的时候走动的方向
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

int n,m;	// 地图大小
bool g[N][N];	// 地图内容
bool vis[N][N];	// 查找的时候标记是否查找过
int k;	// 操作数

int ans;	// ans 是检查岛屿结果

// 查找走动方向
inline bool isRun(int x,int y)
{
	return (x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && g[x][y]);
}

inline void BFS(int x,int y)
{
	// 存储检查坐标
	queue<PII>q;
	q.push(mk(x,y));
	
	while(q.size())
	{
		// 取出当前坐标
		auto now = q.front();
		q.pop();
		
		// 标记已检查大陆坐标
		vis[now.x][now.y] = true;
		
		// 开始尝试往上下左右四个方向
		// 寻找大陆所形成的岛屿
		for(int i = 0;i < 4;++i)
		{
			
			// 取出下一步检查的坐标
			int bx = now.x + dx[i];
			int by = now.y + dy[i];
			
			// 判断是否符合检查走动的条件
			if(isRun(bx,by))
			{
				// 符合则开始标记
				vis[bx][by] = true;
				
				// 列入下一步检查点
				q.push(mk(bx,by));
			}			
		}	
	}
	return ;
}


inline void solve()
{
	// 控制输出格式
	bool st = false;
	
	cin >> n >> m >> k;
	
	while(k--)
	{
		// 开始放置大陆
		int x,y;
		cin >> x >> y;
		
		// 控制的空格输出格式
		if(st) putchar(' ');
		
		// 如果坐标合法,那么开始放置大陆
		if(x >= 0 && x < n && y >= 0 && y < m)
		{
			// 每次放置大陆的时候,我们都要重新
			// BFS 一遍查找连通块,所以这里要初始化标记
			ans = 0;
			memset(vis,false,sizeof vis);
			
			// 放置大陆
			g[x][y] = true;
			
			for(int i = 0;i < n;++i)
			{
				for(int j = 0;j < m;++j)
				{
					// 如果该大陆没被检查过
					if(!vis[i][j] && g[i][j])
					{
						// 累加岛屿
						++ans;
						// 开始检查
						BFS(i,j);
					}
				}
			}		
			
			// 输出岛屿数量结果
			cout << ans;
		}else
		{
			// 如果做标是非法情况,那么我们直接输出上一次的检查结果
			cout << ans;
		}
		
		// 控制输出格式
		st = true;
	}	
}


int main()
{
//	freopen("a.txt", "r", stdin);
//	___G;
	int _t = 1;
//	cin >> _t;
	while (_t--)
	{
		solve();
	}

	return 0;
}

最后提交:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值