DFS/BFS专练-搞定图论基础!(从海岛问题过渡至图论基础应用C++/C)
:: 图论基础理论 :: 紧接着,图论基础理论中,咱们讲到,图论的遍历主要由(dfs与bfs决定)
那咱们本篇博客就来聊聊dfs与bfs。
dfs(深度优先搜索)、bfs(广度优先搜索)的区别:
- dfs(深度优先),就如名字一般,优先不断向下探索。不到黄河不回头,一直到达了绝境之后,才会回溯到原本的位置,然后换个方向,用同样的方式继续遍历。
- bfs(广度优先),优先遍历与本节点相连的所有节点。遍历完毕之后,到达下一个节点,继续用同样的方式遍历。
为什么要讲两种遍历方式呢,因为在创建 邻接表 与 邻接矩阵 之后,想要运用,最基本的就是遍历。
当然、想要掌握一个知识点,靠的从来不是纯概念。
接下来,咱们用dfs遍历邻接表与邻接矩阵。用来练手。
DFS(深度优先搜索)
DFS(深度优先遍历)模版:
void dfs(参数){if(终止条件){存放结果;return;}for(选择:本节点相连的其他节点){处理节点dfs(图,选择的节点);回溯,撤销处理的结果}
}
那咱们根据例题,实战一下吧。
98. 所有可达路径
题目描述
给定一个有 n 个节点的有向无环图,节点编号从 1 到 n。请编写一个函数,找出并返回所有从节点 1 到节点 n 的路径。每条路径应以节点编号的列表形式表示。
输入描述
第一行包含两个整数 N,M,表示图中拥有 N 个节点,M 条边
后续 M 行,每行包含两个整数 s 和 t,表示图中的 s 节点与 t 节点中有一条路径
输出描述
输出所有的可达路径,路径中所有节点之间空格隔开,每条路径独占一行,存在多条路径,路径输出的顺序可任意。如果不存在任何一条路径,则输出 -1。
注意输出的序列中,最后一个节点后面没有空格! 例如正确的答案是 `1 3 5`,而不是 `1 3 5 `, 5后面没有空格!
输入示例
5 5 1 3 3 5 1 2 2 4 4 5
输出示例
1 3 5 1 2 4 5
提示信息
用例解释:
有五个节点,其中的从 1 到达 5 的路径有两个,分别是 1 -> 3 -> 5 和 1 -> 2 -> 4 -> 5。
因为拥有多条路径,所以输出结果为:
1 3 5
1 2 4 5或
1 2 4 5
1 3 5
都算正确。数据范围:
- 图中不存在自环
- 图中不存在平行边
- 1 <= N <= 100
- 1 <= M <= 500
利用邻接矩阵进行深搜:
#include <iostream>
#include <vector>
using namespace std;
const int N = 105;
// 定义邻接矩阵,用于存储图的连接关系
// arr[i][j] = 1 表示存在从节点 i 到节点 j 的有向边
int arr[N][N];
// 存储当前正在探索的路径
vector<int> cur;
// 存储所有从节点 1 到节点 n 的路径
vector<vector<int>> res; // 深度优先搜索函数
// k 表示当前正在访问的节点
// n 表示图中节点的总数
void dfs(int k, int n) { // 如果当前节点是目标节点 nif (k == n) { // 将当前路径添加到结果集合中// emplace_back 比 push_back 更高效res.emplace_back(cur); return;}// 遍历所有可能的下一个节点for (int i = 1; i <= n; ++i) { // 如果存在从节点 k 到节点 i 的有向边if (arr[k][i] == 1) { // 将节点 i 添加到当前路径中cur.emplace_back(i); // 递归调用 dfs 函数,继续探索从节点 i 出发的路径dfs(i, n); // 回溯操作,移除最后添加的节点,以便尝试其他路径cur.pop_back(); }}
}int main() {int n, m;// 输入节点数量 n 和边的数量 mcin >> n >> m; // 有向图,存储边的信息for (int i = 0; i < m; ++i) {int x, y;// 输入边的起点 x 和终点 ycin >> x >> y; // 在邻接矩阵中标记存在从节点 x 到节点 y 的有向边arr[x][y] = 1; }// 首先将起始节点 1 存入当前路径cur.emplace_back(1); // 从节点 1 开始进行深度优先搜索dfs(1, n); // 如果没有找到从节点 1 到节点 n 的路径if (res.size() == 0) { // 输出 -1 表示无解cout << -1 << endl; }// 如果找到了从节点 1 到节点 n 的路径else if (res.size() != 0) { // 遍历所有找到的路径for (auto vec : res) { // 输出路径中的每个节点,除了最后一个节点for (int i = 0; i < vec.size() - 1; ++i) { cout << vec[i] << " ";}// 输出路径中的最后一个节点,并换行cout << vec[vec.size() - 1] << endl; }}return 0;
}
利用邻接表进行深搜:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// 定义常量 N,用于表示图中节点数量的上限
const int N = 105;
// 采用邻接表来表示图,graph[i] 存储的是从节点 i 出发能到达的所有节点
// 这里使用 vector<list<int>> 类型,每个元素是一个链表,链表中存储邻接节点
vector<list<int>> graph(N);
// 用于存储当前正在探索的路径
vector<int> cur;
// 用于存储从起点到终点的所有路径
vector<vector<int>> res;// 深度优先搜索函数,k 表示当前所在的节点,n 表示目标节点
void dfs(int k, int n){// 当当前节点 k 等于目标节点 n 时,说明找到了一条从起点到终点的路径if(k==n){// 将当前路径 cur 添加到结果集合 res 中res.emplace_back(cur);return;}// 遍历当前节点 k 的所有邻接节点for(int i : graph[k]) {// 将邻接节点 i 添加到当前路径 cur 中cur.emplace_back(i);// 以邻接节点 i 为当前节点,继续进行深度优先搜索dfs(i, n);// 回溯操作,将邻接节点 i 从当前路径 cur 中移除// 以便尝试其他可能的路径cur.pop_back();}
}int main(){int n,m;// 输入图的节点数量 n 和边的数量 mcin>>n>>m;// 循环 m 次,每次输入一条边的信息for(int i=0; i<m; ++i){int x,y;// 输入边的起点 x 和终点 ycin>>x>>y;// 将终点 y 添加到起点 x 的邻接表中graph[x].emplace_back(y);}// 将起点 1 添加到当前路径 cur 中cur.emplace_back(1);// 从起点 1 开始进行深度优先搜索dfs(1,n);// 如果结果集合 res 为空,说明没有找到从起点到终点的路径if(res.size()==0) cout<<-1<<endl;else {// 遍历结果集合 res 中的每一条路径for(auto vec:res){// 输出路径中除最后一个节点外的其他节点,节点之间用空格分隔for(int i=0; i<vec.size()-1; ++i) cout<<vec[i]<<" ";// 输出路径中的最后一个节点,并换行cout<<vec[vec.size()-1]<<endl;}}return 0;
}
BFS(广度优先搜索)
BFS优先搜索,通常用于解决,最短路径问题。
遍历方式,咱们在上方已经提及(优先遍历与本节点相连的所有节点。遍历完毕之后,到达下一个节点,继续用同样的方式遍历)。
我就直接,引入了Carl的给出的注释图了,如下图所示。
大家对图进行广搜的话,大多数需要一个容器进行媒介。大家习惯性的会用队列进行广度搜索。
但其实不论用队列、还是栈(stack),都行。只不过用栈,是一次正向遍历、一次逆向遍历而已,其实是没有影响的。
这是对图的BFS遍历方式。
// 定义一个二维数组 dir,用于表示四个方向的偏移量
// 分别为:下(1, 0)、上(-1, 0)、右(0, 1)、左(0, -1)
int dir[4][2]={1,0,-1,0,0,1,0,-1};// 定义广度优先搜索函数 bfs
// 参数 grid 是一个二维向量,表示地图或网格
// 参数 used 是一个二维布尔向量,用于标记某个位置是否已经被访问过
void bfs(vector<vector<int>> grid, vector<vector<bool>> used){// 定义一个队列 q,队列中存储的元素是 std::pair<int, int> 类型// 表示网格中的一个坐标点 (x, y)queue<pair<int,int>> q;// 将起始点 (0, 0) 加入队列q.push({0,0});// 当队列不为空时,继续进行广度优先搜索while(!q.empty()){// 获取队列的队首元素,即当前要处理的坐标点auto cur = q.front();// 将队首元素从队列中移除q.pop();// 标记当前坐标点为已访问used[cur.first][cur.second] = true;// 遍历四个方向for(int i=0; i<4; ++i){// 计算当前方向的偏移量后的新坐标 xint x = cur.first+dir[i][0];// 计算当前方向的偏移量后的新坐标 yint y = cur.second+dir[i][1];// 检查新坐标是否越界// 如果越界(x 小于 0 或者 x 大于等于网格的行数,// 或者 y 小于 0 或者 y 大于等于网格的列数),则跳过该方向if(x>=grid.size()||x<0||y>=grid[0].size()||y<0) continue;// 检查新坐标是否未被访问过if(!used[x][y]){// 如果未被访问过,将新坐标加入队列q.push({x,y});}}}
}
工欲善其事,必先利其器
想要讲图学好,就要将dfs与bfs练习熟练。故我们这里通过 “岛屿问题” 磨炼遍历的基本式。
而接下来几道,都将是经典板子题!
大纲:
1、岛屿数量--基本深度优先搜索(dfs),结合去重进行😉
2、岛屿的面积--岛屿数量的进阶版
3、孤岛的总面积--岛屿的面积的变种
4、沉没孤岛--解法与岛屿的总面积刚好相反(但同属一种思想
5、水流问题--逆推法,我觉得解法蛮帅的😎
6、建造最大岛屿--”就是在海上填一块岛屿“,对每一块岛屿打个编号。用map储存。
7、岛屿的周长--只要记录所有1->0的变化,就能找到所有边
8、字符串接龙--遇事不决,直接画图。去重非常重要。(防超时)
9、有向图的完全联通--简单应用used与graph(邻接表)结合。
1、岛屿数量(dfs)
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
后续 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述:
输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。
输入示例:
4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1
输出示例:
3
提示信息
根据测试案例中所展示,岛屿数量共有 3 个,所以输出 3。
数据范围:
- 1 <= N, M <= 50
DFS(解法)
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
// 定义数组的最大长度
const int N = 55;
// 二维数组 arr 用于存储地图信息,1 表示陆地,0 表示海洋
int arr[N][N];
// 二维布尔数组 used 用于标记每个位置是否已经被访问过
bool used[N][N];
// 二维数组 dir 存储四个方向的偏移量,分别是右、左、下、上
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0}; // 深度优先搜索函数,从 (x, y) 位置开始探索相连的陆地
// 可走、可不走
void dfs(int x, int y) {// 遍历四个方向for (int i = 0; i < 4; ++i) {// 计算下一个位置的横坐标int x_cur = x + dir[i][0];// 计算下一个位置的纵坐标int y_cur = y + dir[i][1];// 检查下一个位置是否未被访问过且是陆地if (!used[x_cur][y_cur] && arr[x_cur][y_cur] == 1) { // 标记下一个位置为已访问used[x_cur][y_cur] = true;// 递归调用 dfs 函数,继续从下一个位置探索dfs(x_cur, y_cur);} }
}int main() {int n, m;// 用于记录岛屿的数量int cnt = 0; // 输入地图的行数和列数cin >> n >> m;// 进行基本的储存 // 输入地图信息,将其存储到 arr 数组中for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)cin >> arr[i][j];// 将 used 数组的所有元素初始化为 false,表示所有位置都未被访问过memset(used, false, sizeof used);// 被用过的,通通标记成2 // 遍历地图的每个位置for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j) {// 若当前位置未被访问过且是陆地if (!used[i][j] && arr[i][j] == 1) {// 标记当前位置为已访问used[i][j] = true;// 岛屿数量加 1cnt++;// 从当前位置开始进行深度优先搜索,标记该岛屿的所有陆地为已访问dfs(i, j); }}// 输出岛屿的数量cout << cnt << endl;return 0;
}
BFS(解法)
其实,在岛屿问题中,我们可以看出。
DFS与BFS的主要差别在于,搜索的方式不同,其他的基本遍历方式都是相同的。
而BFS的核心在于用一个容器(queue),来遍历岛屿。
核心函数:
// 广度优先遍历函数
// grid 为二维网格,used 为标记数组,记录每个位置是否已经被访问过
// n 和 m 分别为起始点的行和列
void bfs(const vector<vector<int>> &grid, vector<vector<bool>> &used, int n, int m) {// 创建一个队列,用于存储待访问的节点坐标queue<pair<int, int>> que;// 将起始点的坐标加入队列que.push({n, m});// 标记起始点为已访问used[n][m] = true;// 当队列不为空时,持续进行遍历while (!que.empty()) {// 取出队列头部的节点坐标pair<int, int> cur = que.front();// 将该节点从队列中移除que.pop();// 遍历四个方向for (int i = 0; i < 4; ++i) {// 计算下一个节点的行坐标int nextY = cur.first + dir[i][0];// 计算下一个节点的列坐标int nextX = cur.second + dir[i][1];// 检查下一个节点的坐标是否越界if (nextX < 0 || nextX >= grid[0].size() || nextY < 0 || nextY >= grid.size())// 如果越界,则跳过该方向continue;// 检查下一个节点的值是否为 1 且未被访问过if (grid[nextY][nextX] == 1 && !used[nextY][nextX]) {// 标记下一个节点为已访问used[nextY][nextX] = true;// 将下一个节点的坐标加入队列que.push({nextY, nextX});}}}
}
总体函数:
// bfs 广度遍历
#include "iostream"
#include "vector"
#include "queue"
using namespace std;int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int result = 0;void bfs(const vector<vector<int>> &grid, vector<vector<bool>> &used, int n, int m){ // 广度优先遍历queue<pair<int,int>> que; // 用一队列,来排顺序que.push({n,m}); // 储存while(!que.empty()){pair<int,int> cur = que.front();que.pop();for(int i=0; i<4; ++i){ // 改变四个方向int nextY = cur.first + dir[i][0];int nextX = cur.second + dir[i][1];if(nextX<0 || nextX>=grid[0].size() || nextY<0 || nextY>=grid.size()) continue;if(grid[nextY][nextX]==1 && !used[nextY][nextX]){used[nextY][nextX]=true;que.push({nextY,nextX});}}}
}int main(){int n,m; // n-行,m-列cin>>n>>m;// 准备阶段vector<vector<int>> grid(n,vector<int>(m,0));vector<vector<bool>> used(n,vector<bool>(m, false));for(int i=0; i<n; ++i)for(int j=0; j<m; ++j){cin>>grid[i][j];}// 遍历阶段for(int i=0; i<n; ++i)for(int j=0; j<m; ++j){if(grid[i][j]==1 && !used[i][j]){result++;bfs(grid,used,i,j);}}cout<<result<<endl;return 0;
}
2、岛屿的面积(dfs)
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,计算岛屿的最大面积。岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的最大面积。如果不存在岛屿,则输出 0。
输入示例
4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1
输出示例
4
提示信息
样例输入中,岛屿的最大面积为 4。
数据范围:
- 1 <= M, N <= 50
做过,岛屿数量之后,你会发现本题换汤不换药。
就是在dfs遍历岛屿的过程中。
一共设置了两个变量cur_area、max_area;
cur_area表示当前陆地的最大面积、max_area表示每遍历到一块新的陆地,就根据max_area刷新一次。
如下:
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 55;
int arr[N][N];
bool used[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
int cur_area; // 用于表示面积
int max_area;
// 可走、可不走,天呐
void dfs(int x,int y){for(int i=0; i<4; ++i){int x_cur = x + dir[i][0];int y_cur = y + dir[i][1];if(!used[x_cur][y_cur]&&arr[x_cur][y_cur]==1){ used[x_cur][y_cur]=true;cur_area++;dfs(x_cur,y_cur);} }
}
int main(){int n,m;cin>>n>>m;// 进行基本的储存 for(int i=1; i<=n; ++i)for(int j=1; j<=m; ++j)cin>>arr[i][j];memset(used,false,sizeof used);// 被用过的,通通标记成2 for(int i=1; i<=n; ++i)for(int j=1; j<=m; ++j){if(!used[i][j]&&arr[i][j]==1){cur_area=1;used[i][j]=true;dfs(i,j); max_area=max_area<cur_area?cur_area:max_area; }}cout<<max_area<<endl;return 0;
}
3、孤岛的总面积(dfs)
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
现在你需要计算所有孤岛的总面积,岛屿面积的计算方式为组成岛屿的陆地的总数。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述
输出一个整数,表示所有孤岛的总面积,如果不存在孤岛,则输出 0。
输入示例
4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1
输出示例:
1
提示信息:
在矩阵中心部分的岛屿,因为没有任何一个单元格接触到矩阵边缘,所以该岛屿属于孤岛,总面积为 1。
数据范围:
1 <= M, N <= 50。
其实本题,思路很清奇,(所有单元格都不接触边缘的岛屿)
因为这句话的存在,只要将靠近上、下、左、右四条边的海岛OK掉就行。
然后,对接下来的部分,解决掉。
#include <iostream>
#include <cstring>
using namespace std;
const int N = 55;
int arr[N][N];
bool used[N][N];
int n,m;
int dir[4][2]={1,0,-1,0,0,1,0,-1};void dfs(int x, int y){for(int i=0; i<4; ++i){int cur_x = x+dir[i][0];int cur_y = y+dir[i][1];if(cur_x<0||cur_x>=m||cur_y<0||cur_y>=n) continue;if(used[cur_x][cur_y]||arr[cur_x][cur_y]==0) continue;used[cur_x][cur_y] = true;dfs(cur_x,cur_y);}
}int main(){cin>>m>>n;memset(used, false, sizeof used);for(int i=0; i<m; ++i)for(int j=0; j<n; ++j) cin>>arr[i][j];// 清空边界// 左边for(int i=0; i<m; ++i){if(used[i][0]||arr[i][0]==0) continue;used[i][0] = true;dfs(i,0);}// 右for(int i=0; i<m; ++i){if(used[i][n-1]||arr[i][n-1]==0) continue;used[i][n-1] = true;dfs(i,n-1);}// 上for(int i=0; i<n; ++i){if(used[0][i]||arr[0][i]==0) continue;used[0][i] = true;dfs(0,i);}// 下for(int i=0; i<n; ++i){if(used[m-1][i]||arr[m-1][i]==0) continue;used[m-1][i] = true;dfs(m-1,i);}int cnt = 0;for(int i=0; i<m; ++i) {for (int j = 0; j < n; ++j) { // 我的荣幸if (!used[i][j] && arr[i][j] == 1) cnt++;}}cout<<cnt<<endl;return 0;
}
4、沉没孤岛(dfs)
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
现在你需要将所有孤岛“沉没”,即将孤岛中的所有陆地单元格(1)转变为水域单元格(0)。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出将孤岛“沉没”之后的岛屿矩阵。
输入示例:
4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1
输出示例:
1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1
提示信息:
将孤岛沉没:
数据范围:
1 <= M, N <= 50
其实沉默孤岛,就是在岛屿总面积的基础上,将原本加在cnt的岛屿变为0。然后没啦
#include "iostream"
#include "vector"
using namespace std;int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
void dfs(const vector<vector<int>> &grid, vector<vector<bool>> &used, int x, int y) {used[x][y]=true;for (int i = 0; i < 4; ++i) {int nextX = x + dir[i][0];int nextY = y + dir[i][1];if (nextX < 0 || nextX >= grid.size() || nextY < 0 || nextY >= grid[0].size()) continue;if (grid[nextX][nextY]==1 && !used[nextX][nextY]) {used[nextX][nextY] = true;dfs(grid, used, nextX, nextY);}}
}int main(){int n,m;cin >> n >> m;// 基础储存vector<vector<int>> grid(n,vector<int>(m,0));for(int i=0; i<n; i++){for(int j=0; j<m; j++){cin>>grid[i][j];}}vector<vector<bool>> used(n,vector<bool>(m,false));// 跳转for(int i=0; i<n; ++i){ // n为行if(grid[i][0] && !used[i][0]) dfs(grid,used,i,0);if(grid[i][m-1] && !used[i][m-1]) dfs(grid,used,i,m-1);}for(int i=0; i<m; ++i){// m为列if(grid[0][i] && !used[0][i]) dfs(grid,used,0,i);if(grid[n-1][i] && !used[n-1][i]) dfs(grid,used,n-1,i);}for(int i=0; i<n; ++i){for(int j=0; j<m; ++j){if(grid[i][j] && used[i][j]) cout<<1<<" ";else cout<<0<<" ";}cout<<endl;}return 0;}
5、水流问题
题目描述:
现有一个 N × M 的矩阵,每个单元格包含一个数值,这个数值代表该位置的相对高度。矩阵的左边界和上边界被认为是第一组边界,而矩阵的右边界和下边界被视为第二组边界。
矩阵模拟了一个地形,当雨水落在上面时,水会根据地形的倾斜向低处流动,但只能从较高或等高的地点流向较低或等高并且相邻(上下左右方向)的地点。我们的目标是确定那些单元格,从这些单元格出发的水可以达到第一组边界和第二组边界。
输入描述:
第一行包含两个整数 N 和 M,分别表示矩阵的行数和列数。
后续 N 行,每行包含 M 个整数,表示矩阵中的每个单元格的高度。
输出描述:
输出共有多行,每行输出两个整数,用一个空格隔开,表示可达第一组边界和第二组边界的单元格的坐标,输出顺序任意。
输入示例:
5 5 1 3 1 2 4 1 2 1 3 2 2 4 7 2 1 4 5 6 1 1 1 4 1 2 1
输出示例:
0 4 1 3 2 2 3 0 3 1 3 2 4 0 4 1
提示信息:
图中的蓝色方块上的雨水既能流向第一组边界,也能流向第二组边界。所以最终答案为所有蓝色方块的坐标。
数据范围:
1 <= M, N <= 50
本题中,有一个非常重要的细节,一定要建立记忆话搜索,否则会造成无限递归。
#include <iostream>
#include <cstring>
using namespace std;
// 在本题中,一定要实现记忆话搜索,否则会导致重复遍历一点,从而导致无限递归。
const int N = 105;
int n,m;
int arr[N][N];
int arr_one[N][N];
int arr_two[N][N];
int dir[4][2]={1,0,-1,0,0,1,0,-1};void dfs(int cur_arr[N][N], int flag,int x,int y){ // 要填充的数组、要填充成谁for(int i=0; i<4; ++i){int cur_x = x+dir[i][0];int cur_y = y+dir[i][1];if(cur_x<0||cur_x>=n||cur_y<0||cur_y>=m) continue;if(cur_arr[cur_x][cur_y]!=0) continue; // 这一步记忆化搜索,非常重要 if(arr[x][y]<=arr[cur_x][cur_y]){cur_arr[cur_x][cur_y]=flag; dfs(cur_arr,flag,cur_x,cur_y);}}
}int main(){cin>>n>>m;memset(arr_one,0,sizeof arr_one);memset(arr_two,0,sizeof arr_two);for(int i=0; i<n; ++i)for(int j=0; j<m; ++j) cin>>arr[i][j];for(int i=0; i<n; ++i){// 左arr_one[i][0]=1;dfs(arr_one,1,i,0);// 右arr_two[i][m-1]=2;dfs(arr_two,2,i,m-1);}for(int i=0; i<m; ++i){// 上arr_one[0][i]=1;dfs(arr_one,1,0,i);// 下arr_two[n-1][i]=2;dfs(arr_two,2,n-1,i);}for(int i=0; i<n; ++i)for(int j=0; j<m; ++j)if(arr_one[i][j]==1&&arr_two[i][j]==2) cout<<i<<" "<<j<<endl;return 0;
}
6、建造最大岛屿
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,你最多可以将矩阵中的一格水变为一块陆地,在执行了此操作之后,矩阵中最大的岛屿面积是多少。
岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设矩阵外均被水包围。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述:
输出一个整数,表示最大的岛屿面积。
输入示例:
4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1
输出示例
6
提示信息
对于上面的案例,有两个位置可将 0 变成 1,使得岛屿的面积最大,即 6。
数据范围:
1 <= M, N <= 50。
如果硬写本题的话,时间复杂度n*n*n *n。
岛屿问题,最大的特点就是染色,故,我们可以对每一块岛屿染色,或者是打上特殊标记。
通过unordered_map标记,描绘其对应的值。对应的值。
#include <iostream>
#include <unordered_map>
#include <unordered_set>
using namespace std;
const int N = 55;
int n,m;
int arr[N][N]; // 集合
int dir[4][2]={1,0,-1,0,0,1,0,-1};
void dfs(int x, int y, int mark, int& cnt){if(x<0||x>=n||y<0||y>=m) return;if(arr[x][y]!=1) return; cnt++;arr[x][y]=mark;for(int i=0; i<4; ++i){dfs(x+dir[i][0],y+dir[i][1],mark,cnt);}
}int main(){ cin>>n>>m; for(int i=0; i<n; ++i)for(int j=0; j<m; ++j) cin>>arr[i][j];int mark = 2; // 用于标记unordered_map<int,int> umap;for(int i=0; i<n; ++i){for(int j=0; j<m; ++j){if(arr[i][j]!=1) continue;int cnt = 0; // 用于计数dfs(i,j,mark,cnt); umap[mark++]=cnt;}}unordered_set<int> uset;int max_all=0;for(int i=0; i<n; ++i){for(int j=0; j<m; ++j){if(arr[i][j]!=0) continue;uset.clear();int all = 1;for(int k=0; k<4; ++k){int x = i+dir[k][0];int y = j+dir[k][1];if(x<0||x>=n||y<0||y>=m) continue;if(uset.find(arr[x][y])!=uset.end()) continue;all += umap[arr[x][y]];uset.insert(arr[x][y]);}max_all = max(max_all,all); }}if(max_all==0) cout<<umap[arr[0][0]]<<endl;else cout<<max_all<<endl;return 0;
}
7、岛屿的周长
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。
你可以假设矩阵外均被水包围。在矩阵中拥有一个或者多个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的周长。
输入示例
5 5 0 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0
输出示例
14
提示信息
岛屿的周长为 14。
数据范围:
1 <= M, N <= 50。
从上方给出的图片,我们可以看出。只有“1”与“0”的交界处,是可以计入周长的边。
if(x<0||x>=n||y<0||y>=m){ // 越界 cnt++;return;}if(arr[x][y]==0){cnt++;return;}
所以可以根据,返回条件,进行cnt++,然后return;
#include <iostream>
using namespace std;
const int N = 55;
int n,m;
int arr[N][N];
bool used[N][N];
int dir[4][2]={1,0,-1,0,0,1,0,-1}; int cnt=0;
void dfs(int x, int y){if(x<0||x>=n||y<0||y>=m){ // 越界 cnt++;return;}if(used[x][y]) return; // 被遍历过if(arr[x][y]==0){cnt++;return;}used[x][y]=true;for(int i=0; i<4; ++i){int cur_x = x + dir[i][0];int cur_y = y + dir[i][1];dfs(cur_x, cur_y); }
}int main(){cin>>n>>m;for(int i=0; i<n; ++i)for(int j=0; j<m; ++j) cin>>arr[i][j];for(int i=0; i<n; ++i)for(int j=0; j<m; ++j){if(arr[i][j]==1){dfs(i,j);cout<<cnt<<endl;return 0; }}return 0;
}
8、字符串接龙
题目描述
字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:
序列中第一个字符串是 beginStr。
序列中最后一个字符串是 endStr。
每次转换只能改变一个位置的字符(例如 ftr 可以转化 fty ,但 ftr 不能转化 frx)。
转换过程中的中间字符串必须是字典 strList 中的字符串。
beginStr 和 endStr 不在 字典 strList 中
字符串中只有小写的26个字母
给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。
输入描述
第一行包含一个整数 N,表示字典 strList 中的字符串数量。 第二行包含两个字符串,用空格隔开,分别代表 beginStr 和 endStr。 后续 N 行,每行一个字符串,代表 strList 中的字符串。
输出描述
输出一个整数,代表从 beginStr 转换到 endStr 需要的最短转换序列中的字符串数量。如果不存在这样的转换序列,则输出 0。
输入示例
6 abc def efc dbc ebc dec dfc yhn
输出示例
4
提示信息
从 startStr 到 endStr,在 strList 中最短的路径为 abc -> dbc -> dec -> def,所以输出结果为 4
数据范围:
2 <= N <= 500
去重是非常有必要的,如果不去重,在输入结果大时,会导致结果超时。
而本题,画过图之后,思路会清晰很多:
遇题不会,直接上纸。
// 用get_cnt(args) 用来判断,两个字符串相差几个字母
// 用广搜 搜索方便找到最短路径。
// 用umap去重,并存储搜索的长度。
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <queue>
using namespace std;
// 如果,非要讲解这道题目的话,无非就两点,把图画出来,直接秒变最短路径
// 去重,是相当重要的一点。
// 基本标记
unordered_map<string,int> umap;
unordered_set<string> uset;bool get_cnt(string str1, string str2){ // true:刚好合格 if(str1.size()!=str2.size()) return false;int cnt = 0;for(int i=0; i<str1.size(); ++i){if(str1[i]!=str2[i]) cnt++;} if(cnt!=1) return false;return true;
} int main(){int n;string begin_str,end_str;cin>>n>>begin_str>>end_str;for(int i=0; i<n; ++i){string str;cin>>str;uset.insert(str);} queue<pair<string,int>> q;q.emplace(begin_str,1);while(!q.empty()){auto node = q.front();q.pop();string str = node.first;int cnt = node.second; if(get_cnt(str,end_str)){cout<<cnt+1<<endl;return 0;}for(auto str_cur : uset){if(umap.find(str_cur)!=umap.end()) continue;if(!get_cnt(str,str_cur)) continue;umap.emplace(str_cur,cnt+1);q.emplace(str_cur,cnt+1); }}cout<<0<<endl;return 0;
}
9、有向图的完全联通
【题目描述】
给定一个有向图,包含 N 个节点,节点编号分别为 1,2,...,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
【输入描述】
第一行包含两个正整数,表示节点数量 N 和边的数量 K。 后续 K 行,每行两个正整数 s 和 t,表示从 s 节点有一条边单向连接到 t 节点。
【输出描述】
如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
【输入示例】
4 4 1 2 2 1 1 3 2 4
【输出示例】
1
【提示信息】
从 1 号节点可以到达任意节点,输出 1。
数据范围:
- 1 <= N <= 100;
- 1 <= K <= 2000。
// 用邻接表graph存储所有节点。
// 用used表示,遍历过该节点,顺便去重
// 最后,根据used内,是否有节点未被遍历过,来判断结果
#include <iostream>
#include <cstring>
#include <list>
#include <vector>
using namespace std;
const int N = 105;
int used[N];
vector<list<int>> graph(N); int n,m;
void dfs(int i){if(used[i]!=0) return;used[i]=1;for(int node : graph[i]) dfs(node);
}
int main(){cin>>n>>m;for(int i=0; i<m; ++i){int s,t;cin>>s>>t;graph[s].push_back(t); }dfs(1);for(int i=1; i<=n; ++i) if(used[i]==0){cout<<-1<<endl;return 0;} cout<<1<<endl;return 0;
}
借鉴博客:
1、深度优先理论
相关文章:
DFS/BFS专练-搞定图论基础!(从海岛问题过渡至图论基础应用C++/C)
:: 图论基础理论 :: 紧接着,图论基础理论中,咱们讲到,图论的遍历主要由(dfs与bfs决定) 那咱们本篇博客就来聊聊dfs与bfs。 dfs(深度优先搜索)、bfs(广度优先搜索)的区别…...
2024年RIS SCI2区:自适应天鹰算法AAO,深度解析+性能实测
目录 1.摘要2.天鹰算法AO原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 智能电网通过集成可再生能源并管理供需动态平衡来提高效率,本文提出了自适应天鹰算法(AAO),AAO使用Sigmoid因子来平衡探索和开发,根据迭…...
orcad csi 17.4 DRC规则设置及检查
rCAD绘制完原理图之后总是需要开启DRC检测,但是DRC一般都是英文版的,下面基于Cadence17.4 的orCAD16.6 对DRC的界面做简单的介绍 首先,鼠标点击原理图,然后再点击右上方的小勾图标 desine rules check option选项的界面 电气规…...
前端实战:基于 Vue 与 QRCode 库实现动态二维码合成与下载功能
在现代 Web 应用开发中,二维码的应用越来越广泛,从电子票务到信息传递,它都扮演着重要角色。本文将分享如何在 Vue 项目中,结合QRCode库实现动态二维码的生成、与背景图合成以及图片下载功能,打造一个完整且实用的二维…...
天梯赛DFS合集
1.DFS特殊输入:PTA | 程序设计类实验辅助教学平台 这题其他还是蛮容易,直接用递归即可,问题在于怎么输入,其实可以在递归到底层时输入即可,也就是边递归边输入,另外提一嘴跟这个题没什么关系的点ÿ…...
Qt中读写结构体字节数据
在Qt中读写结构体字节数据通常涉及将结构体转换为字节数组(QByteArray)或直接从内存中读写。以下是几种常见方法: 方法1:使用QDataStream读写结构体 cpp #include <QFile> #include <QDataStream>// 定义结构体 #pragma pack(push, 1) //…...
关于yarn和hadoop
1.yarn的定义? YARN(Yet Another Resource Negotiator)是 Apache Hadoop 的一个关键组件,它是一个资源管理平台,负责管理和调度计算资源。YARN 允许多个数据处理引擎(如 MapReduce、Spark、Flink 等&#…...
【全部更新】2025妈妈杯D题1-4问mathercupD题数学建模挑战赛D题数学建模思路代码文章教学短途运输货量预测及车辆调度问题
完整内容请看文章最下面的推广群 先进行摘要和结果的展示、再给出完整的思路 问题1:通过时间序列或机器学习模型预测货量,并按历史分布拆分到10分钟颗粒度。 问题2:基于货量生成运输需求,用贪心算法或整数规划优化车辆调度。 问…...
考研408第一章计算机系统概述——1.1-1.2操作系统的基本概念与发展历程
考研408计算机系统概述——操作系统的基本概念与发展历程 一、操作系统的基本概念 1.1 操作系统的定义与功能 1.1.1 定义 操作系统(Operating System, OS)是管理计算机硬件与软件资源的程序集合,为应用程序和用户提供接口与服务。其核心功能包括: 资源管理者:处理机、…...
《从理论到实践:CRC校验的魔法之旅》
循环冗余校验(Cyclic Redundancy Check ,CRC )是一种用于检测数据传输或存储过程中错误的算法。他通过计算数据的校验值(也称为CRC码),并在数据接收端验证校验值是饭否正确,从而检测数据是否在传输过程中被…...
【算法笔记】整除与最大公约数(GCD)专题整理
参考文章链接(已获得作者授权) 一、整除:数学中的"完美分割" 定义 若整数 a a a能整除整数 b b b(记作 a ∣ b a\mid b a∣b),则存在整数 k k k使得 b a ⋅ k ba\cdot k ba⋅k。 通俗理解&…...
JDBC 与 MyBatis 详解:从基础到实践
目录 一、JDBC 介绍 二、使用 JDBC 查询用户信息 三、ResultSet 结果集 四、预编译 SQL - SQL 注入问题 五、预编译 SQL - 性能更高 六、JDBC 增删改操作 插入数据: 更新数据: 删除数据: 七、MyBatis 介绍 八、MyBatis 入门程序 引…...
虚拟机开发环境搭建与内网迁移
以下是关于在虚拟机中搭建开发环境并迁移至内网的详细步骤及注意事项,适用于需要在内网隔离环境中进行开发的场景(如企业安全要求、离线开发等): 一、虚拟机开发环境搭建 1. 选择虚拟机平台 推荐工具: V…...
【HFP】蓝牙HFP协议音频连接核心技术深度解析
目录 一、音频连接建立的总体要求 1.1 发起主体与时机 1.2 前提条件 1.3 同步连接的建立 1.4 通知机制 二、不同主体发起的音频连接建立流程 2.1 连接建立触发矩阵 2.2 AG 发起的音频连接建立 2.3 HF 发起的音频连接建立 三、编解码器连接建立流程 3.1 发起条件 3.…...
PowerBI 表格显示无关联的表数据
假设有两张没有建立关联的数据表: 产品表 库存表 我们将他们放入表格里显示,数据会出问题。 因为 [库存表] 里的数据有除 [产品表] 以外的产品的数据,所以PBI无法从两张表中找到一一对应的数据。 解决方法:(不建立关联关系的情况下) 新建一个度量值&a…...
观察者模式详解与C++实现
1. 模式定义 观察者模式(Observer Pattern)是一种行为型设计模式,定义了对象间的一对多依赖关系。当一个对象(被观察者/主题)状态改变时,所有依赖它的对象(观察者)都会自动收到通知…...
用ffmpeg 实现拉取h265的flv视频转存成264的mp4 实现方案
1.需要对ffmpeg进行源码修改 这里使用 https://github.com/numberwolf/FFmpeg-QuQi-H265-FLV-RTMP 这位大神提供的源码 需要 x265_3.2.1.tar.gz last_x264.tar.bz2 fdk-aac-2.0.1.tar.gz FFmpeg-QuQi-H265-FLV-RTMP-master.zip 这些包 升级ubuntu18.04 apt update a…...
《AI赋能职场:大模型高效应用课》第8课 AI辅助职场沟通与协作
【本课目标】 掌握AI辅助邮件、沟通话术的优化技巧。学习利用AI快速生成高效的会议纪要。通过实操演练,提升职场沟通效率与协作能力。 【准备工具】 DeepSeek大模型(deepseek.com)百度文心一言(yiyan.baidu.com) 一…...
PowerBI下载安装教程
1、打开官方下载链接,或者Microsoft store里搜索下载(通过官网下载可以选择安装路径,应用商店直接会安装到默认路径里)。 2、等待下载成功后,直接点击【打开】即可。...
PowerBI如何钻取到明细
PowerBI如何钻取到明细 最近做项目领导提到一需求,在查看账龄的时候,还想查看到它的一个明细情况。 PowerBI如何钻取到明细,以一个案例分享下: 第一步:我们先查看账龄的一个分布情况: 第二步:…...
常见算法题
import java.util.*;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val val;this.left left;this.right right;} }public class test_04_16 {//获取二叉…...
C语言超详细结构体知识
1.自定义类型:结构体的介绍 在之前的博客中,我们简单介绍过了关于结构体的基本知识,这里我们稍微复习一下。 结构体(struct)是C语言中一种重要的复合数据类型,它允许将不同类型的数据组合成一个整体。 1.1结构体的定义 结构体使…...
2N60-ASEMI功业控制与自动化专用2N60
编辑:ll 2N60-ASEMI功业控制与自动化专用2N60 型号:2N60 品牌:ASEMI 封装:TO-220F 批号:最新 最大漏源电流:2A 漏源击穿电压:600V RDS(ON)Max:5.00Ω…...
发现“横”字手写有难度,对比两个“横”字
我发现手写体“横”字“好看”程度,难以比得上印刷体: 两个从方正简体启体来的“横”字: 哪个更好看?我是倾向于左边一点。 <div style"transform: rotate(180deg); display: inline-block;"> 左边是我从方正简…...
深入解析 HTML5 Web IndexedDB 数据库:构建高效离线应用的基石
摘要 在现代 Web 应用开发中,离线访问和高效处理大量结构化数据的需求日益增长。HTML5 的 IndexedDB 作为一种强大的客户端 NoSQL 数据库,为开发者提供了可靠的解决方案。本文将全面介绍 IndexedDB 的特性、语法、方法、应用实例、使用场景,以及其优势与劣势,帮助开发者深…...
17-算法打卡-哈希表-快乐数-leetcode(202)-第十七天
1 题目地址 202. 快乐数 - 力扣(LeetCode)202. 快乐数 - 编写一个算法来判断一个数 n 是不是快乐数。「快乐数」 定义为: * 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 * 然后重复这个过程直到这个数变为 1…...
决战浏览器渲染:减少重绘(Repaint)与重排(Reflow)的性能优化策略
在现代Web开发中,流畅的用户体验是衡量应用质量的关键指标之一。用户与界面的每一次交互,背后都牵动着浏览器复杂而精密的渲染过程。当这个过程不够高效时,用户就会感受到卡顿、延迟,甚至页面“掉帧”。在众多影响渲染性能的因素中…...
深度解析生成对抗网络:原理、应用与未来趋势
在人工智能的浩瀚星空中,生成对抗网络(Generative Adversarial Networks,GAN)犹如一颗璀璨的明星,自 2014 年由 Ian Goodfellow 等人提出以来,便以其独特而强大的生成能力,在计算机视觉、自然语…...
电能质量治理解决方案:构建高效、安全的电力系统
随着“双碳”目标的推进及新型电力系统的快速发展,大量电力电子设备(如光伏逆变器、充电桩、变频器等)接入电网,导致谐波畸变、无功功率激增、电压波动等问题日益突出。电能质量恶化不仅威胁设备安全,还影响电网稳定运…...
生态篇|多总线融合与网关设计
引言 1. 车内多总线概览 2. 主流车载总线技术对比 3. 网关设计原则与架构 4. 协议转换与映射策略 5. 安全与诊断功能集成...
热门与冷门并存,25西电—电子工程学院(考研录取情况)
1、电子工程学院各个方向 2、电子工程学院近三年复试分数线对比 学长、学姐分析 由表可看出: 1、电子科学与技术25年相较于24年上升20分 2、信息与通信工程、控制科学与工程、新一代电子信息技术(专硕)25年相较于24年下降25分 3、25vs24推…...
HDFS入门】HDFS安全与权限管理解析:从认证到加密的完整指南
目录 引言 1 认证与授权机制 1.1 Kerberos认证集成 1.2 HDFS ACL细粒度控制 2 数据加密保护 2.1 传输层加密(SSL/TLS) 2.2 静态数据加密 3 审计与监控体系 3.1 操作审计流程 3.2 安全监控指标 4 权限模型详解 4.1 用户/组权限模型 4.2 umask配置原理 5 安全最佳实…...
合成数据中的对抗样本生成与应用:让AI模型更强、更稳、更安全
目录 合成数据中的对抗样本生成与应用:让AI模型更强、更稳、更安全 一、什么是对抗样本? 二、为什么要在合成数据中引入对抗样本? 三、对抗样本在图像合成数据中的生成方法 ✅ 方法1:FGSM(Fast Gradient Sign Met…...
考研系列-计算机网络-第二章、物理层
一、通信基础 1.物理层基本概念 2.数据通信基础知识...
uni-app 安卓10以上上传原图解决方案
在Android 10及以上版本中,由于系统对文件访问的限制,使用chooseImage并勾选原图上传后,返回的是图片的外部存储路径,如:file:///storage/emulated/0/DCIM/Camera/。这种外部存储路径,无法直接转换成所需要…...
关于element的dialog的取消(关闭弹窗)方法触发两次
在这里插入图片描述 关闭的时候加个修饰符.native close.native...
vue,uniapp解决h5跨域问题
如果有这样的跨域问题,解决办法: ✅ 第一步:在项目根目录下创建 vue.config.js 和 package.json 同级目录。 // vue.config.js module.exports {devServer: {proxy: {/api: {target: https://app.yycjkb.cn, // 你的后端接口地址changeOrig…...
2025-04-18 李沐深度学习3 —— 线性代数
文章目录 1 线性代数1.1 标量、向量与矩阵1.2 矩阵概念1.3 按特定轴求和 2 实战:线性代数2.1 标量2.2 向量2.3 矩阵2.4 张量2.5 降维2.6 点积2.7 矩阵-向量积2.8 矩阵-矩阵乘法2.9 范数2.10 练习 1 线性代数 1.1 标量、向量与矩阵 标量(Scalarÿ…...
2026《数据结构》考研复习笔记三(C++高级教程)
C高级教程 一、文件和流二、异常处理三、命名空间四、模板五、信号处理六、多线程 一、文件和流 iostream 用于标准输入/输出(控制台I/O),处理与终端(键盘输入和屏幕输出)的交互 包含以下全局流对象: cin&…...
python进阶: 深入了解调试利器 Pdb
Python是一种广泛使用的编程语言,以其简洁和可读性著称。在开发和调试过程中,遇到错误和问题是不可避免的。Python为此提供了一个强大的调试工具——Pdb(Python Debugger)。 Pdb是Python标准库中自带的调试器,可以帮助…...
前端资源加载失败后重试加载(CSS,JS等引用资源)
前端资源加载失败后的重试 .前端引用资源时出现了资源加载失败(这里针对的是路径引用异常或者url解析错误时) 解决这个问题首先要明确一下几个步骤 1.什么情况或者什么时候重试 2.如何重试 3.重试过程中的边界处理 这里引入里三个测试脚本,分别加载里三个不同的脚…...
每日算法【双指针算法】(Day 2-复写零)
双指针算法 1.算法题目(复写零)2.讲解算法原理3.编写代码 1.算法题目(复写零) 注意:不要越界,不能开额外的数组,只能从现有数组上进行操作,没有返回值。 2.讲解算法原理 解法:双指针操作 先根据“异地”操作…...
【C++深入系列】:模版详解(上)
🔥 本文专栏:c 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 你不需要很厉害才能开始,但你需要开始才能很厉害。 ★★★ 本文前置知识: 类和对象(上) …...
PyCharm Flask 使用 Tailwind CSS v3 配置
安装 Tailwind CSS 步骤 1:初始化项目 在 PyCharm 终端运行:npm init -y安装 Tailwind CSS:npm install -D tailwindcss3 postcss autoprefixer初始化 Tailwind 配置文件:npx tailwindcss init这会生成 tailwind.config.js。 步…...
设计模式每日硬核训练 Day 15:享元模式(Flyweight Pattern)完整讲解与实战应用
🔄 回顾 Day 14:组合模式小结 在 Day 14 中,我们学习了组合模式(Composite Pattern): 适用于构建树状层级结构,使得“单个对象”和“对象集合”统一操作。广泛用于文件系统、UI 控件树、组织结…...
使用Service发布应用程序
使用Service发布应用程序 文章目录 使用Service发布应用程序[toc]一、什么是Service二、通过Endpoints理解Service的工作机制1.什么是Endpoints2.创建Service以验证Endpoints 三、Service的负载均衡机制四、Service的服务发现机制五、定义Service六、Service类型七、无头Servic…...
美家市场2025电视版分享码-美家市场电视直播软件分享码免费获取
美家市场2025电视版作为一款备受欢迎的应用市场,为用户提供了海量的电视直播软件,而分享码则是免费获取这些资源的重要途径。与此同时,乐看家桌面也是一款在智能电视领域极具特色的软件,它能与美家市场搭配使用,为用户…...
动手学深度学习:手语视频在NiN模型中的测试
前言 NiN模型是在LeNet的基础上修改,提出了1x1卷积层和全局平均池化层的概念,减少了全连接所带来的参数量很多的问题。本篇在之前代码的基础上添加了模型保存,loss和acc记录以及记录模型时间等功能,所以模型后面的代码会重新记录…...
医院数据中心智能化数据上报与调数机制设计
针对医院数据中心的智能化数据上报与调数机制设计,需兼顾数据安全性、效率性、合规性及智能化能力。以下为系统性设计方案,分为核心模块、技术架构和关键流程三部分: 一、核心模块设计 1. 数据上报模块 子模块功能描述多源接入层对接HIS/LIS/PACS/EMR等异构系统,支持API/E…...
Ubuntu命令速查
当你在Ubuntu系统中需要快速查询常用命令时,可以使用以下速查表: 列出文件和目录: ls切换目录: cd [目录路径]显示当前工作目录的绝对路径: pwd创建新目录: mkdir [目录名]删除文件或目录: rm […...