航拍地图问题(细胞问题)
1. 问题描述
Jacky在网上发布了通过无人机航拍的某海域的地图,该海域有很多岛屿,为了能更好地分析该区域的航拍地图,地图被数字化为0到9组成矩阵,0表示该位置为大海,数字1到9代表该位置为陆地,沿非0数字上下左右还是非0数字则为同一陆地,求给定的数字化航拍地图中陆地的个数。
【输入格式】
第1行为两整数m,n(m行,n列)
第2行开始是一个m*n的矩阵
【输出格式】
只有1行,为矩阵中的陆地的个数。
【输入样例】
4 11
04523000815
90345605000
60456006711
00000000894
【输出样例】
4
2. 算法思想
使用广度优先搜索,遍历地图的每一个位置,递归出口就是当前搜索的位置已经被搜索过、超出地图范围,或者该位置是海水。这样从一块陆地的任何一个位置开始搜索,一旦所有的层次的递归全部结束,就表示这一块陆地查找结束。
数字化题图采用二维数组的形式存储。
数组说明:int *map*[M][N]
(开辟M*N个空间,下标[0][0]~[M-1][N-1]
),陆地标记为1,海水标记为0,搜索过的位置也同样标记为0。
3. 完整代码
public class Item_02 {
static int m;
static int n;
static int sum = 0;//陆地个数
static int[][] map; //标记地图状况,0为海水
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
m = in.nextInt();
n = in.nextInt();
map = new int[m][n];
String line;
int tmp = 0;
line = in.nextLine();
//读取地图,海水标记为0,陆地标记为1
for(int i=0;i<m;i++) {
line = in.nextLine(); //读取一行数字转化为数组
for(int j=0;j<n;j++) {
tmp = Integer.valueOf(line.substring(j, j+1));
if(tmp!=0) {
map[i][j] = 1;
}
}
}
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
if(map[i][j]!=0) {
sum++;
BFS(i,j);
}
}
}
System.out.println(sum);
}
/**
* 广度优先搜索获得陆地个数
* @param map
*/
private static void BFS(int i, int j) {
if(i<0 || j<0|| i>=m || j>=n || map[i][j]==0) { //某个结点为海水直接结束
return;
}
map[i][j] = 0;
BFS(i-1,j); //向上查找
BFS(i+1,j); //向下查找
BFS(i,j-1); //向左查找
BFS(i,j+1); //向右查找
}
}
4. 测试
输入标准数据测试,3行11列的数据,得到结果为5块陆地。
为了测试算法的正确性,又输入了特殊值进行验证,输入一组1行11列的数据,经检验,结果正确。