左神算法基础class5—题目5岛问题

1.题目:岛问题

一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?
举例:
0 0 1 0 1 0
1 1 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
这个矩阵中有三个岛。

2.分析

本题的思路很简单,对矩阵中的每个元素进行遍历。如果当前元素为1时,岛的数量加1,再把当前元素改为2(表示这个岛已经记录过),递归查找其上下左右四个元素,如果有元素为1,继续改为2(相邻为1是同一个岛,已经记录过),不断递归上下左右四个元素直至元素不为1或查找越界。

3.核心代码

(1)递归求岛的范围

我们把递归函数定义为infect,函数功能像感染一样,如果找到元素值为1,不断在周围四个元素查找是否有值为1的元素。
注意:
①递归直接返回的条件是数组越界和当前元素值不为1;
②需要先将当前元素值改为2再递归,不然会不断循环查找

void infect(int a[][width],int j,int i)  //传二维数组需将第二维指定
{
	if(j < 0||j >= width ||i < 0|| i >= height || a[i][j] != 1)
		return;
	a[i][j] = 2;
	//查找上下左右四个元素
	infect(a,j - 1,i);
	infect(a,j + 1,i);
	infect(a,j,i - 1);
	infect(a,j,i + 1);
}

(2)求岛的数量

对矩阵进行遍历,如果发现元素值为1的元素,岛的数量增加1并调用递归函数找出整个岛。最后返回岛的数量。

int countIslands(int a[][width])
{
	int num = 0;
	for(int i = 0;i < height;i++)
	{
		for(int j = 0;j < width;j++)
		{
			if(a[i][j] == 1)
			{
				num++;
				infect(a,j,i);
			}
		}
	}
	return num;
}

4.完整代码

#include<iostream>
//#include<vector>
using namespace std;
#define width 6
#define height 4

void infect(int a[][width],int j,int i)
{
	if(j < 0||j >= width ||i < 0|| i >= height || a[i][j] != 1)
		return;
	a[i][j] = 2;
	infect(a,j - 1,i);
	infect(a,j + 1,i);
	infect(a,j,i - 1);
	infect(a,j,i + 1);
}

int countIslands(int a[][width])
{
	int num = 0;
	for(int i = 0;i < height;i++)
	{
		for(int j = 0;j < width;j++)
		{
			if(a[i][j] == 1)
			{
				num++;
				infect(a,j,i);
			}
		}
	}
	return num;
}

int main()
{
	int a[height][width] = {
		{0,0,1,0,1,0},
		{1,1,1,0,1,0},
		{1,0,0,1,0,0},
		{0,0,0,0,0,0}};
	cout<<countIslands(a);

	system("pause");
	return 0;
}

5.扩展:并行问题

如果问对于很大的矩阵如何解决。使用并行思想,将岛一分为n,分别处理。处于边界的岛可能会多算,因为如果边界上相邻的岛都为1时,每部分会分别记录,总和就多算了。解决的方案是:设计变量,记录每一个岛的起始位置。这样再检查边界时,如果两个岛起始位置不同,岛的数量减1(实际是一个岛),再把两个岛合并起始位置相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值