代码随想录算法训练营day52:图03:101. 孤岛的总面积;102. 沉没孤岛;103. 水流问题
101. 孤岛的总面积
卡码网:101. 孤岛的总面积(opens new window)
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
现在你需要计算所有孤岛的总面积,岛屿面积的计算方式为组成岛屿的陆地的总数。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述
输出一个整数,表示所有孤岛的总面积,如果不存在孤岛,则输出 0。
我的算法dfs:
在dfs的基础上,分别计算每次孤岛的面积,计入thissize,计算完后加到total上
每次遇到一个陆地且未访问过:进行dfs访问
核心:一旦遇到一个陆地接触到了边界——那么thissize将始终归为0
即使thissize归为0,也需要计算把相接处的陆地visit掉
所以,采用了在dfs函数开头分类讨论:
遇到边界了——size为0
本情况非孤岛,size已经为0了——永远为0
初始情况,size记为-1,且初始情况 不涉及到边界——size=1
否则初始情况标记为0,会和非孤岛 size已经为0混淆
其他情况下size++
注意:初始情况,是怎么被启动的!!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>int move[4][2]={1,0,0,1,-1,0,0,-1};
int this_size;void dfs(int i,int j,int **box,int**visit,int m,int n){if(i<=0 || i>=n-1 || j<=0 || j>=m-1 || this_size==0){this_size=0;}else if(this_size==-1) this_size=1;else this_size++;for(int k=0;k<4;k++){int move_i = i+move[k][0];int move_j = j+move[k][1];if(move_i >=0 && move_i<n && move_j>=0 && move_j<m && box[move_i][move_j]==1 && visit[move_i][move_j]==0){visit[move_i][move_j]=1;//printf("in:%d %d size=%d\n",move_i,move_j,this_size);dfs(move_i,move_j,box,visit,m,n);}}
}int main(){int n,m;scanf("%d%d",&n,&m);int** box=(int**)malloc(sizeof(int*)*n);int **visit=(int**)malloc(sizeof(int*)*n);for (int i=0;i<n;i++){box[i]=(int*)malloc(sizeof(int)*m);visit[i]=(int*)malloc(sizeof(int)*m);for(int j=0;j<m;j++){scanf("%d",&box[i][j]);visit[i][j]=0;}}int total_area=0;for (int i=0;i<n;i++){for(int j=0;j<m;j++){if(box[i][j]==1 && visit[i][j]==0){this_size=-1;visit[i][j]=1;dfs(i,j,box,visit,m,n);total_area=total_area+this_size;}}}printf("%d",total_area);return 0;
}
改成bfs:
int front=-1;
int rear=-1;
int queue[10000][2];bool judge(int i,int j,int n,int m){if(i<= 0 || i>=n-1 || j<=0 || j>=m-1) return true;else return false;
}void bfs(int i,int j,int**box,int**visit,int m,int n){rear++;queue[rear][0]=i;queue[rear][1]=j;visit[i][j]=1;if(judge(i,j,n,m)) this_size=0;else this_size=1;while(front!=rear){front++;int xi=queue[front][0];int xj=queue[front][1];for(int k=0;k<4;k++){int fi=xi+move[k][0];int fj=xj+move[k][1];if(fi>=0 && fi<n && fj>=0 && fj<m && box[fi][fj]==1 && visit[fi][fj]==0){if(judge(fi,fj,n,m) || this_size==0) this_size=0;else this_size++;rear++;queue[rear][0]=fi;queue[rear][1]=fj;visit[fi][fj]=1;}}}
}
或者
也可以考虑:
本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图 统计此时还剩下的陆地就可以了。
如图,在遍历地图周围四个边,靠地图四边的陆地,都为绿色,

在遇到地图周边陆地的时候,将1都变为0,此时地图为这样:

102. 沉没孤岛
卡码网题目链接(ACM模式)(opens new window)
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
现在你需要将所有孤岛“沉没”,即将孤岛中的所有陆地单元格(1)转变为水域单元格(0)。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出将孤岛“沉没”之后的岛屿矩阵。
分析:
思路依然是从地图周边出发,将周边空格相邻的陆地都做上标记,然后在遍历一遍地图,遇到 陆地 且没做过标记的,那么都是地图中间的 陆地 ,全部改成水域就行。
有的录友可能想,我在定义一个 visited 二维数组,单独标记周边的陆地,然后遍历地图的时候同时对 数组board 和 数组visited 进行判断,决定 陆地是否变成水域。
这样做其实就有点麻烦了,不用额外定义空间了,标记周边的陆地,可以直接改陆地为其他特殊值作为标记。
步骤一:深搜或者广搜将地图周边的 1 (陆地)全部改成 2 (特殊标记)
步骤二:将水域中间 1 (陆地)全部改成 水域(0)
步骤三:将之前标记的 2 改为 1 (陆地)
如图:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>int move[4][2]={1,0,0,1,-1,0,0,-1};void dfs(int i,int j,int**box,int **visit,int m,int n){visit[i][j]=1;box[i][j]=2;for(int k=0;k<4;k++){int movei=i+move[k][0];int movej=j+move[k][1];if(movei>=0 && movej>=0 && movei<n && movej<m && visit[movei][movej]==0 && box[movei][movej]==1){dfs(movei,movej,box,visit,m,n);}}
}int main(){int n,m;scanf("%d%d",&n,&m);int** box=(int**)malloc(sizeof(int*)*n);int **visit=(int**)malloc(sizeof(int*)*n);for (int i=0;i<n;i++){box[i]=(int*)malloc(sizeof(int)*m);visit[i]=(int*)malloc(sizeof(int)*m);for(int j=0;j<m;j++){scanf("%d",&box[i][j]);visit[i][j]=0;}}for (int i=0;i<n;i++){if(box[i][0]==1 && visit[i][0]==0){dfs(i,0,box,visit,m,n);}if(box[i][m-1]==1 && visit[i][m-1]==0){dfs(i,m-1,box,visit,m,n);}}for (int i=0;i<n;i++){if(box[0][i]==1 && visit[0][i]==0){dfs(0,i,box,visit,m,n);}if(box[n-1][i]==1 && visit[n-1][i]==0){dfs(n-1,i,box,visit,m,n);}}for (int i=0;i<n;i++){for(int j=0;j<m;j++){if(box[i][j]==1) box[i][j]=0;else if(box[i][j]==2) box[i][j]=1;printf("%d ",box[i][j]);}printf("\n");}return 0;
}
或者bfs:
int front=-1,rear=-1;
int queue[1000][2];void bfs(int i,int j,int**box,int **visit,int m,int n){rear++;queue[rear][0]=i;queue[rear][1]=j;visit[i][j]=1;box[i][j]=2;while(rear!=front){front++;int xi=queue[front][0];int xj=queue[front][1];for(int k=0;k<4;k++){int movei=xi+move[k][0];int movej=xj+move[k][1];if(movei>=0 && movej>=0 && movei<n && movej<m && visit[movei][movej]==0 && box[movei][movej]==1){rear++;queue[rear][0]=movei;queue[rear][1]=movej;visit[movei][movej]=1;box[movei][movej]=2;}}}}
103. 水流问题
卡码网题目链接(ACM模式)(opens new window)
题目描述:
现有一个 N × M 的矩阵,每个单元格包含一个数值,这个数值代表该位置的相对高度。矩阵的左边界和上边界被认为是第一组边界,而矩阵的右边界和下边界被视为第二组边界。
矩阵模拟了一个地形,当雨水落在上面时,水会根据地形的倾斜向低处流动,但只能从较高或等高的地点流向较低或等高并且相邻(上下左右方向)的地点。我们的目标是确定那些单元格,从这些单元格出发的水可以达到第一组边界和第二组边界。
输入描述:
第一行包含两个整数 N 和 M,分别表示矩阵的行数和列数。
后续 N 行,每行包含 M 个整数,表示矩阵中的每个单元格的高度。
输出描述:
输出共有多行,每行输出两个整数,用一个空格隔开,表示可达第一组边界和第二组边界的单元格的坐标,输出顺序任意。
分析:
一、从高往低寻找
小的数 无法继承大的数的遍历结果,导致每个数字都必须从头遍历,复杂度太高
遍历每一个节点,是 m * n,遍历每一个节点的时候,都要做深搜,深搜的时间复杂度是: m * n
那么整体时间复杂度 就是 O(m^2 * n^2) ,这是一个四次方的时间复杂度。

二、从低往高
从第一组边界上的节点 逆流而上,将遍历过的节点都标记上。
同样从第二组边界的边上节点 逆流而上,将遍历过的节点也标记上。
然后两方都标记过的节点就是既可以流太平洋也可以流大西洋的节点。
从第一组边界边上节点出发,如图:

从第二组边界上节点出发,如图:

关于dfs函数搜索的过程 时间复杂度是 O(n * m),这个大家比较容易想。
关键看主函数,那么每次dfs的时候,上面还是有for循环的。
第一个for循环,时间复杂度是:n * (n * m) 。
第二个for循环,时间复杂度是:m * (n * m)。
所以本题看起来 时间复杂度好像是 : n * (n * m) + m * (n * m) = (m * n) * (m + n) 。
其实这是一个误区,大家再自己看 dfs函数的实现,其实 有visited函数记录 走过的节点,而走过的节点是不会再走第二次的。
所以 调用dfs函数,只要参数传入的是 数组 firstBorder,那么地图中 每一个节点其实就遍历一次,无论你调用多少次。
同理,调用dfs函数,只要 参数传入的是 数组 secondBorder,地图中每个节点也只会遍历一次。
所以,以下这段代码的时间复杂度是 2 * n * m。 地图用每个节点就遍历了两次,参数传入 firstBorder 的时候遍历一次,参数传入 secondBorder 的时候遍历一次。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>int move[4][2]={1,0,0,1,-1,0,0,-1};int main(){int n,m;scanf("%d%d",&n,&m);int** box=(int**)malloc(sizeof(int*)*n);int **visit1=(int**)malloc(sizeof(int*)*n);int **visit2=(int**)malloc(sizeof(int*)*n);for (int i=0;i<n;i++){box[i]=(int*)malloc(sizeof(int)*m);visit1[i]=(int*)malloc(sizeof(int)*m);visit2[i]=(int*)malloc(sizeof(int)*m);for(int j=0;j<m;j++){scanf("%d",&box[i][j]);visit1[i][j]=0;visit2[i][j]=0;}}for (int i=0;i<n;i++){if(visit1[i][0]==0) dfs(i,0,box,visit1,m,n);if(visit2[i][m-1]==0) dfs(i,m-1,box,visit2,m,n); }for (int i=0;i<m;i++){if(visit1[0][i]==0) dfs(0,i,box,visit1,m,n);if( visit2[n-1][i]==0) dfs(n-1,i,box,visit2,m,n);}for (int i=0;i<n;i++){for(int j=0;j<m;j++){if(visit1[i][j]==1 && visit2[i][j]==1) printf("%d %d\n",i,j); }}return 0;
}
bfs:
int front=-1,rear=-1;
int queue[1000][2];void bfs(int i,int j,int**box,int **visit,int m,int n){rear++;queue[rear][0]=i;queue[rear][1]=j;visit[i][j]=1;while(rear!=front){front++;int xi=queue[front][0];int xj=queue[front][1];for(int k=0;k<4;k++){int movei=xi+move[k][0];int movej=xj+move[k][1];if(movei>=0 && movej>=0 && movei<n && movej<m && visit[movei][movej]==0 && box[movei][movej]>=box[xi][xj]){rear++;queue[rear][0]=movei;queue[rear][1]=movej;visit[movei][movej]=1;}}}}
相关文章:
代码随想录算法训练营day52:图03:101. 孤岛的总面积;102. 沉没孤岛;103. 水流问题
101. 孤岛的总面积 卡码网:101. 孤岛的总面积(opens new window) 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单…...
开源大模型本地私有化部署
1、安装ollama ollma下载 https://ollama.com/download/windows linux 安装 curl -fsSL https://ollama.com/install.sh | sh 运行 ollama run gemma:2b ollama run gemma:7b 使用端口11434 2、下载 open-webui 代码 https://github.com/open-webui/open-webui.git 生成目录…...
站长为什么要搭建个人博客网站
搭建个人博客网站是一个值得考虑的选择,它不仅有助于个人成长,还能在多个方面带来积极的影响。以下是几个主要的理由: 一、记录与备忘 方便回顾与查阅:博客网站成为了一个个人知识库,记录下来的内容方便后续查阅和回顾…...
Golang | Leetcode Golang题解之第355题设计推特
题目: 题解: type Twitter struct {Tweets []intUserTweets map[int][]intFollows map[int][]intIsFollowMy map[int]bool }/** Initialize your data structure here. */ func Constructor() Twitter {// 每一次实例化的时候,都重新分配一次…...
Redis如何实现发布/订阅?
引言 Redis是一款高性能的内存数据存储系统,除了常用的键值存储功能外,还提供了发布/订阅(Pub/Sub)机制。通过发布/订阅机制,Redis可以实现消息的广播或者实时通知功能,是一种非常有用的功能。 本文将详细…...
EmguCV学习笔记 VB.Net 4.4 图像形态学
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问:EmguCV学习笔记 C# 目录-CSD…...
HarmonyOS 开发
环境 下载IDE 代码 import { hilog } from kit.PerformanceAnalysisKit; import testNapi from libentry.so; import { router } from kit.ArkUI; import { common, Want } from kit.AbilityKit;Entry Component struct Index {State message: string Hello HarmonyOS!;p…...
拒绝拖延!Kimi助你一天内速成论文初稿!
撰写学术论文是一项需要周密计划和精确执行的任务。它要求作者对文章的每个部分进行深入思考,以确保论文结构的合理性和论述的清晰度。利用Kimi的功能,我们可以更系统地进行写作,从构思到最终成稿,逐步构建出一篇高质量的学术论文…...
Python画笔案例-005 绘制迷宫
1、绘制迷宫 通过 python 的turtle 库绘制一个迷宫的图案,如下图: 2、实现代码 从图上可以看出,内测最短的竖线开始,每次右转 90 度后,线段都增加 8 个单位,所以我们是用 for 循环,循环 50 次…...
【鸿蒙学习】HarmonyOS应用开发者高级认证 - 应用性能优化二(代码层面)
学完时间:2024年8月22日 学完排名:第1801名 一、长列表优化概述 列表是应用开发中最常见的一类开发场景,它可以将杂乱的信息整理成有规律、易于理解和操作的形式,便于用户查找和获取所需要的信息。应用程序中常见的列表场景有新…...
【Docker】如何将A机器内的镜像,导入到B机器?
由于网络或者仓库的原因,经常遇到pull拉取镜像失败的情况!! 那么,如何将A机器内的镜像,通过命令,导入到B机器? 两条重要的命令: 1,在已经成功拉取pull的机器上执行命令…...
动手实现基于Reactor模型的高并发Web服务器(一):epoll+多线程版本
系统流程概览 main函数 对于一个服务器程序来说,因为要为外部的客户端程序提供网络服务,也就是进行数据的读写,这就必然需要一个 socket 文件描述符,只有拥有了文件描述符 C/S 两端才能通过 socket 套接字进行网络通信࿰…...
爬虫案例4——爬取房天下数据
简介:个人学习分享,如有错误,欢迎批评指正 任务:从房天下网中爬取小区名称、地址、价格和联系电话 目标网页地址:https://newhouse.fang.com/house/s/ 一、思路和过程 目标网页具体内容如下: …...
网络硬盘录像机NVR程序源码NVR全套运用方案
在当今社会,随着科技的飞速发展和人们对安全需求的日益增长,安防监控系统已成为保障公共安全、维护社会稳定的重要手段。其中,网络视频录像机(NVR)作为安防监控系统的核心设备,其智能化升级运用方案对于提高…...
03:电容的充放电特性及应用举例
1.电容的基本特性:电容两端的电压不能突变 2.影响电容两端电压的参数:整个回路中电阻,电容大小 3.如何计算电容的电压变化时间? τRC R1k C1uF 则得到τ1ms的时间 应用:芯片使能延时...
【专题】2023-2024中国游戏企业研发竞争力报告合集PDF分享(附原数据表)
原文链接: https://tecdat.cn/?p37447 在当今的数字时代,游戏产业已然成为经济与文化领域中一股不可忽视的重要力量。2023 年,中国自研游戏市场更是呈现出一片繁荣且复杂的景象,实际销售收入达到了令人瞩目的 2563.8 亿元&#x…...
会话跟踪方案:Cookie Session Token
什么是会话技术? Cookie 以登录为例,用户在浏览器中将账号密码输入并勾选自动登录,浏览器发送请求,请求头中设置Cookie:userName:张三 ,password:1234aa ,若登录成功,服务器将这个cookie保存…...
jemeter压力测试入门
1. 安装jemeter的压缩包并且解压 点击运行 2. 添加线程组 3. 线程组的参数设置 4. 添加http请求 5. 填写请求信息 添加监听器——结果树(结果),聚合报告(吞吐量报告) 6. 通过cvs数据文件设置,配置元件&…...
SpringBoot3 简单集成 Spring AI 并使用
文章目录 准备JDK17api key 创建项目编写配置文件创建controller启动并测试角色预设流式响应\异步响应ChatModel(聊天模型)ImageModel(文生图)文生语音语言翻译多模态Function Calling (函数调用第三方API)…...
【C/C++】程序设计基础知识(数据类型与表达式、控制语句、数组与结构)
【C/C】程序设计基础知识(数据类型与表达式、控制语句、数组与结构) 一、数据类型与表达式1.1C语言符号1.2C语言运算符1.3数据类型1.4常量与变量1.5基本运算1.6优先级和结合性1.7输入与输出 二、控制语句2.1顺序结构2.2选择结构2.3循环结构2.4break,cont…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
