蓝桥杯-岛屿个数-bfs-dfs算法

小蓝得到了一副大小为 M × N 的格子地图,可以将其视作一个只包含字符‘0’(代表海水)和 ‘1’(代表陆地)的二维数组,地图之外可以视作全部是海水,每个岛屿由在上/下/左/右四个方向上相邻的 ‘1’ 相连接而形成。

在岛屿 A 所占据的格子中,如果可以从中选出 k 个不同的格子,使得他们的坐标能够组成一个这样的排列:(x0, y0),(x1, y1), . . . ,(xk−1, yk−1),其中(x(i+1)%k , y(i+1)%k) 是由 (xi , yi) 通过上/下/左/右移动一次得来的 (0 ≤ i ≤ k − 1),

此时这 k 个格子就构成了一个 “环”。如果另一个岛屿 B 所占据的格子全部位于这个 “环” 内部,此时我们将岛屿 B 视作是岛屿 A 的子岛屿。若 B 是 A 的子岛屿,C 又是 B 的子岛屿,那 C 也是 A 的子岛屿。

请问这个地图上共有多少个岛屿?在进行统计时不需要统计子岛屿的数目。

输入格式

第一行一个整数 T,表示有 T 组测试数据。

接下来输入 T 组数据。对于每组数据,第一行包含两个用空格分隔的整数M、N 表示地图大小;接下来输入 M 行,每行包含 N 个字符,字符只可能是‘0’ 或 ‘1’。

输出格式

对于每组数据,输出一行,包含一个整数表示答案。

#include <iostream>
#include <queue>
using namespace std;
typedef pair<int, int>pii;  //结果提二维
const int N = 100;
int n, m;
int g[N][N];      //模拟二维图

bool st_sea[N][N];  //是否走过海
bool st_road[N][N]; //是否走过陆地

int dsx[8] = { -1,-1, -1,0,1,1,1,0};   //海的8个方向遍历
int dsy[8]={-1,0,1,1,1,0,-1,-1};

int drx[4] = { -1,0,1,0 };            //陆地的4个方向编列
int dry[4] = { 0,1,0,-1 };

int ans=0;
void bfs_road(int x, int y);
bool check(int x,int y)
{
	return (x >= 0 && x < n && y >= 0 && y < m);

}

void bfs_sea(int x,int y)
{
	st_sea[x][y] = true; //访问这个海坐标
	queue<pii>q;
	q.push({ x,y });
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		for (int i = 0; i < 8; i++)
		{
			int nx = t.first + dsx[i];
			int ny = t.second + dsy[i];
			if (check(nx, ny) && !g[nx][ny] && !st_sea[nx][ny])
			{
				st_sea[nx][ny] = true;
				q.push({ nx,ny });

			}
			if (check(nx, ny) && g[nx][ny] && !st_road[nx][ny])
			{
				ans++;
				bfs_road(nx, ny);
			}
		}
	}
}

//bfs算法
//void bfs_road(int x, int y)
//{
//	st_road[x][y] = true;
//	queue<pii> qr;
//	qr.push({ x, y });
//	while (qr.size())
//	{
//		auto t = qr.front();
//		qr.pop();
//		for (int i = 0; i < 4; i++)
//		{
//			int nx =t.first+drx[i];
//			int ny = t.second+dry[i];
//			if (check(nx, ny) && g[nx][ny] && !st_road[nx][ny])
//			{
//				st_road[nx][ny] = true;
//				qr.push({ nx,ny });
//			}
//		}
//	}
//}

//dfs算法
void bfs_road(int x, int y)
{
	st_road[x][y] = true;
	for (int i = 0; i < 4; i++)   //循环为递归的条件
	{
		int nx = x + drx[i];
		int ny = y + dry[i];
		if (check(nx, ny) && g[nx][ny] && !st_road[nx][ny])  //找到未遍历的递归
		{
			st_road[nx][ny] = true;
			bfs_road(nx, ny);
		}
	}
}

void solve()
{
	   ans = 0;
	cin >> n >> m;
	for (int i = 0; i < n; i++)        //初始化被访问的标记
	{
		for (int j = 0; j < m; j++)
		{
			st_sea[i][j] = st_road[i][j] = false;
		}
	}
	for (int i = 0; i < n; i++)    //输入每一行的标记
	{
		string s;
		cin >> s;
		for (int j = 0; j < m; j++)
			g[i][j] = s[j] - '0';
	}
	bool flag = false;   //判断特殊情况的印记

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			
			if (!i || !j ||i == n - 1 || j == m - 1)
				if (!g[i][j] && !st_sea[i][j])
				{
					flag = true;
					bfs_sea(i, j);	
				}
				 
		}
	if (!flag) ans=1;
	cout << ans << endl;
}
signed main()
{
	ios::sync_with_stdio;
	cin.tie(0);
	cout.tie(0);
	int num = 1;
	while (num--)
	{
		solve();
			
	}
}

### 关于DFSBFS算法的练习题及相关解析 #### 一、DFS(深度优先搜索) DFS的核心思想是从某个起点开始,尽可能深地探索每一个分支,直到无法再深入为止。以下是几个经典的DFS题目及其解析: 1. **岛屿数量** - **描述**: 给定一个由 '1' (陆地) 和 '0' (水) 组成的二维网格,计算岛屿数量岛屿总是被水包围,并且是由相邻陆地连接而成的区域。 - **示例代码**: ```python def numIslands(grid): if not grid or not grid[0]: return 0 m, n = len(grid), len(grid[0]) visited = [[False]*n for _ in range(m)] def dfs(x, y): if x < 0 or x >= m or y < 0 or y >= n or grid[x][y] == "0" or visited[x][y]: return visited[x][y] = True directions = [(0,1),(1,0),(-1,0),(0,-1)] # 右 下 上 左 for dx, dy in directions: nx, ny = x + dx, y + dy dfs(nx, ny) count = 0 for i in range(m): for j in range(n): if grid[i][j] == "1" and not visited[i][j]: dfs(i, j) count += 1 return count ``` 这里通过递归的方式实现了DFS逻辑[^2]。 2. **迷宫问题** - **描述**: 在给定的一个矩阵中,从起始点到达终点的所有路径数是多少? - **解析**: 使用DFS尝试每一条可能的路径,当遇到障碍物或超出边界时停止当前路径的扩展[^3]。 --- #### 二、BFS(广度优先搜索) BFS是一种逐层展开的搜索方式,适合解决最短路径类问题。以下是几个典型的BFS题目及其解析: 1. **克隆图** - **描述**: 给定无向连通图中一个节点的引用,返回其深拷贝(即克隆)。每个节点都含有一个 `val` (整数值)和一个列表 `neighbors` 表示它的邻居节点。 - **示例代码**: ```python from collections import deque class Node: def __init__(self, val=0, neighbors=None): self.val = val self.neighbors = neighbors if neighbors is not None else [] def cloneGraph(node): if not node: return None queue = deque([node]) clones = {node: Node(node.val)} while queue: current = queue.popleft() for neighbor in current.neighbors: if neighbor not in clones: clones[neighbor] = Node(neighbor.val) queue.append(neighbor) clones[current].neighbors.append(clones[neighbor]) return clones[node] ``` 2. **腐烂橘子** - **描述**: 在一个二维网格中,有新鲜橘子和腐烂橘子。每一分钟,任何与腐烂橘子相邻的新鲜橘子都会变质。求所有橘子全部腐烂所需的最少时间。 - **解析**: 利用队列记录每次需要处理的状态变化,逐步扩散感染范围直至没有新的可感染对象[^4]。 --- #### 三、综合应用实例 以下是一个结合了DFS/BFS的应用场景——图像染色问题: - **输入**: 图像数组 `image`, 起始坐标 `(sr, sc)` 和新颜色 `newColor`. - **目标**: 将与初始位置相同颜色的所有相连像素替换为指定的新颜色。 - **解决方案**: 如果旧颜色等于新颜色,则无需执行任何操作;否则可以通过DFSBFS完成任务。具体实现见上述“岛屿数量”的变形版本。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值