给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。 岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
图一
图二
依次遍历叠代的普通算法
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
// 给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
// 网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
// 岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
int _grid[][4] = { {0,1,0,0},{1,1,1,0},{0,1,0,0},{1,1,0,0} };
int main ()//预处理用二维数组来存放0和1表示陆地和岛屿
{//主要思路:2个for循环依次遍历这个二维数组,然后第三个for循环对每一个陆地的方格按照(右下左上)的顺序依次遍历
//k分别为0 ,1,2,3对应(右下左上)四个顺序依次遍历,tx表示变化后的行数,ty表示变化后的列数,以每个(遍历到的陆地中间)方格作为 o点建立直角坐标系,如图二:是当i=0,j=1时,按照1,2,3,4的顺序依次遍历
//分别判断1,2,3,4所对应的边是否为 海岸线(岛屿周长的一条边)
const int dx[4] = { 0, 1, 0, -1 };
const int dy[4] = { 1, 0, -1, 0 };
int sum = 0;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (_grid[i][j])//如果判断为1,则是岛屿,则进去for循环里面,判断这块岛屿相邻的四条边是否为海岸线
{
int cnt = 0;
for (int k = 0; k < 4; ++k)
{
int tx = i + dx[k];
int ty = j + dy[k];
if (tx < 0 || tx >= 4 || ty < 0 || ty >= 4 || !_grid[tx][ty])//
{//这个条件是判断是否海岸线的的一条边,tx < 0 || tx >= 4 || ty < 0 || ty >= 4 因为中间是岛屿,若它四周越界,则也计算为海岸线
//若它相邻的也是岛屿,则两个岛屿中间的边不算海岸线
cnt += 1;//每一次cnt都初始化从0开始,最大是4,,计算完每块方格后把cnt结果加给sum累加
}
}
sum += cnt;
}
}
}
cout << sum;
}
DFS(深度优先搜索算法)
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//DFS
// 给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
// 网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
// 岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
int _grid[][4] = {{0,1,0,0},{1,1,1,0},{0,1,0,0},{1,1,0,0}};
int dfs(int x, int y, vector< vector<int> > &grid, int n, int m)
{//先看大步骤3:
const int dx[4] = {0, 1, 0, -1};//朝右下左上四个方向的代码
const int dy[4] = {1, 0, -1, 0};//朝右下左上四个方向的代码
if (x < 0 || x >= n || y < 0 || y >= m || grid[x][y] == 0)
{//如果该相邻方格越界或者为海洋,则返回值为1,res+1;
return 1;
}
if(grid[x][y] == 2)//这个是判断是否以及遍历过该方格的步骤,若已经遍历过则返回值为0
{
return 0;
}
grid[x][y] = 2;//每一次遍历过方格后都将该方格标记为1
int res = 0;
for(int i = 0; i < 4; ++i)
{
int tx = x + dx[i];//朝右下左上四个方向的代码
int ty = y + dy[i];//朝右下左上四个方向的代码
res += dfs(tx, ty, grid, n, m);//这相当于一个递归,也是dfs的核心,朝着符合条件的深度方向去寻找
//直至不符合条件,再一重重地跳出递归语句
//这个过程人脑力难以一点点地描述具体步骤出来,我来讲下大体思路,先看大步骤2:从[0][0]开始向右遍历到[0][1]发现陆地,进入dfs函数
//分别向4个方向依次遍历判断是否符合海岸线的边界,遍历过的方格就标记为二,下次再遇见他时就不需要遍历,接着传递新的tx,ty参数给x和y
//递归循环dfs向深处搜索,直至不符合条件跳出递归
}
return res;
}
//看大步骤2:
void DFS_islandPerimeter(vector< vector<int> > &grid)
{//n表示第一行有n个元素,m表示有m个[0]行这样的元素,即有m行,n列
int n = grid.size(), m = grid[0].size();
int sum = 0;
for(int i = 0; i < n; ++i)
{//两个for循环依次遍历这个动态二维数组的每一个元素
for(int j = 0; j < m; ++j)
{//当判断到是陆地 grid[i][j] == 1
if(grid[i][j] == 1)
{//进入到dfs这个自定义函数中,以该方格为平面直角坐标向四个方向依次遍历(右下左上)
sum += dfs(i, j, grid, n, m);
}
}
}
cout << sum;
}
int main()
{
//先看大步骤1:
//先建立一个动态一维数组t,并把 _grid[][4]静态二维数组
//通过for循环存储到动态二维数组grid里 ,需要调用头文件 #include<vector>
vector< vector<int> > grid; //格式
vector<int> t;
for(int i = 0; i < 4; ++i)
{//依次存储值到这个动态二维数组里
t.clear();//每一次 动态一维数组t将数连接给动态二维数组grid后,清空t,目的是节省空间
for(int j = 0; j < 4; ++j)
{
t.push_back(_grid[i][j]);//把每一行的静态一维数组_grid连接到动态一维数组t的尾端
}
grid.push_back(t);//将每一行的动态一维数组连接到动态二维数组的下一行(尾端)
}//下面是调用DFS这个自定义的子函数
DFS_islandPerimeter(grid);//传递参数这个动态二维数组的首地址
}
建议读者将代码复制到编译器上,调试看看过程,创作不易,感谢读者的观看。感谢支持