DFS(深度优先算法)难


给定一个 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);//传递参数这个动态二维数组的首地址 
}

建议读者将代码复制到编译器上,调试看看过程,创作不易,感谢读者的观看。感谢支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值