目录
一、存储矩阵的两种方式
输入示例一:
第一行包含两个整数 N,M,表示图中拥有 N 个节点,M 条边
后续 M 行,每行包含两个整数 s 和 t,表示图中的 s 节点与 t 节点中有一条路径
5 5
1 3
3 5
1 2
2 4
4 5
输入示例二:
第一行包含两个整数 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、邻接矩阵
邻接矩阵使用二维数组来表示图结构。 邻接矩阵是从节点的角度来表示图,有多少节点就申请多大的二维数组。
例如: grid[2][5] = 6,表示节点 2 连接节点 5 为有向图,节点 2 指向节点 5,边的权值为 6。
如果想表示无向图,即:grid[2][5] = 6,grid[5][2] = 6,表示节点 2 与节点 5 相互连通,权值为 6。
ACM模式输入邻接矩阵(对应示例一):
int N, M;
cin >> N >> M;
vector<vector<int>> graph(N, vector<int>(N, 0));
int s, t;
for (int i = 0; i < M; i++)
{
cin >> s >> t;
graph[s][t] = 1;
}
ACM模式输入邻接矩阵(对应示例二):
int N, M;
cin >> N >> M;
vector<vector<int>> graph(N, vector<int>(M, 0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
cin >> graph[i][j];
}
}
2、邻接表
邻接表使用数组 + 链表的方式来表示。邻接表是从边的数量来表示图,有多少边才会申请对应大小的链表。
ACM模式输入邻接表(对应示例一):
int N, M;
cin >> N >> M;
vector<list<int>> graph(N);
int s, t;
for (int i = 0; i < M; i++)
{
cin >> s >> t;
graph[s].push_back(t);
}
二、所有可能的路径(深搜基础)
原题力扣797 . - 力扣(LeetCode)
1、核心代码模式
vector<vector<int>> result;
vector<int> path;
void dfs(vector<vector<int>>& graph, int curNode, int n)
{
if (curNode == n - 1) // 终止条件:找到目标节点
{
result.push_back(path); // 保存结果
return;
}
for (int i = 0; i < graph[curNode].size(); i++)
{
path.push_back(graph[curNode][i]); // 保存至路径
dfs(graph, graph[curNode][i], n); // 进入下一层
path.pop_back(); // 回溯
}
}
vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph)
{
int n = graph.size();
path.push_back(0);
dfs(graph, 0, n);
return result;
}
2、ACM模式(邻接矩阵)
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> result;
vector<int> path;
void dfs(vector<vector<int>>& graph, int curNode, int n)
{
if (curNode == n - 1)
{
result.push_back(path);
return;
}
for (int i = 0; i < n; i++)
{
if (graph[curNode][i] == 1)
{
path.push_back(i);
dfs(graph, i, n);
path.pop_back();
}
}
}
int main()
{
int N, M;
cin >> N >> M;
vector<vector<int>> graph(N, vector<int>(N, 0));
int s, t;
for (int i = 0; i < M; i++)
{
cin >> s >> t;
graph[s][t] = 1;
}
path.push_back(1);
dfs(graph, 1, N);
if (result.size() == 0)
{
cout << -1 << endl;
}
for (int i = 0; i < result.size(); i++)
{
for (int j = 0; j < result[i].size(); j++)
{
cout << result[i][j];
if (j != result[i].size() - 1)
{
cout << " ";
}
}
cout << endl;
}
return 0;
}
3、ACM模式(邻接表)
#include <iostream>
#include <vector>
#include <list>
using namespace std;
vector<vector<int>> result;
vector<int> path;
void dfs(vector<list<int>>& graph, int curNode, int n)
{
if (curNode == n - 1)
{
result.push_back(path);
return;
}
for (int x : graph[curNode])
{
path.push_back(x);
dfs(graph, x, n);
path.pop_back();
}
}
int main()
{
int N, M;
cin >> N >> M;
vector<list<int>> graph(N);
int s, t;
for (int i = 0; i < M; i++)
{
cin >> s >> t;
graph[s].push_back(t);
}
path.push_back(1);
dfs(graph, 1, N);
if (result.size() == 0)
{
cout << -1 << endl;
}
for (int i = 0; i < result.size(); i++)
{
for (int j = 0; j < result[i].size(); j++)
{
cout << result[i][j];
if (j != result[i].size() - 1)
{
cout << " ";
}
}
cout << endl;
}
return 0;
}
三、岛屿数量
原题力扣200 . - 力扣(LeetCode)
1、深度优先搜索
int dirs[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
void dfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y, int n, int m)
{
for (const auto& dir : dirs)
{
int nextX = x + dir[0];
int nextY = y + dir[1];
if (nextX >= n || nextX < 0 || nextY >= m || nextY < 0)
{
continue;
}
if (!visited[nextX][nextY] && grid[nextX][nextY] == '1')
{
visited[nextX][nextY] = true;
dfs(grid, visited, nextX, nextY, n, m);
}
}
}
int numIslands(vector<vector<char>>& grid)
{
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> visited(n, vector<bool>(m, false));
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (!visited[i][j] && grid[i][j] == '1')
{
visited[i][j] = true;
ans++;
dfs(grid, visited, i, j, n, m);
}
}
}
return ans;
}
2、广度优先搜索
int dirs[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y, int n, int m)
{
queue<pair<int, int>> que;
que.push({ x, y });
visited[x][y] = true;
while (!que.empty())
{
pair<int, int> curNode = que.front();
que.pop();
for (const auto& dir : dirs)
{
int nextX = curNode.first + dir[0];
int nextY = curNode.second + dir[1];
if (nextX >= n || nextX < 0 || nextY >= m || nextY < 0)
{
continue;
}
if (!visited[nextX][nextY] && grid[nextX][nextY] == '1')
{
que.push({ nextX, nextY });
visited[nextX][nextY] = true;
}
}
}
}
int numIslands(vector<vector<char>>& grid)
{
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> visited(n, vector<bool>(m, false));
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (!visited[i][j] && grid[i][j] == '1')
{
ans++;
bfs(grid, visited, i, j, n, m);
}
}
}
return ans;
}
3、并查集
四、岛屿的最大面积
原题力扣695 . - 力扣(LeetCode)
1、深度优先搜索
int dirs[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
int count;
void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y, int n, int m)
{
for (const auto& dir : dirs)
{
int nextX = x + dir[0];
int nextY = y + dir[1];
if (nextX >= n || nextX < 0 || nextY >= m || nextY < 0)
{
continue;
}
if (!visited[nextX][nextY] && grid[nextX][nextY] == 1)
{
visited[nextX][nextY] = true;
count++; // 找到新的陆地格,计数器加1
dfs(grid, visited, nextX, nextY, n, m);
}
}
}
int maxAreaOfIsland(vector<vector<int>>& grid)
{
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> visited(n, vector<bool>(m, false));
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (!visited[i][j] && grid[i][j] == 1)
{
count = 1; // 找到新的岛,重置计数器
visited[i][j] = true;
dfs(grid, visited, i, j, n, m);
ans = max(ans, count);
}
}
}
return ans;
}
2、广度优先搜索
int dirs[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
int count;
void bfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y, int n, int m)
{
queue<pair<int, int>> que;
que.push({ x, y });
visited[x][y] = true;
while (!que.empty())
{
pair<int, int> curNode = que.front();
que.pop();
for (const auto& dir : dirs)
{
int nextX = curNode.first + dir[0];
int nextY = curNode.second + dir[1];
if (nextX >= n || nextX < 0 || nextY >= m || nextY < 0)
{
continue;
}
if (!visited[nextX][nextY] && grid[nextX][nextY] == 1)
{
que.push({ nextX, nextY });
count++; // 找到新的陆地格,计数器加1
visited[nextX][nextY] = true;
}
}
}
}
int maxAreaOfIsland(vector<vector<int>>& grid)
{
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> visited(n, vector<bool>(m, false));
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (!visited[i][j] && grid[i][j] == 1)
{
count = 1; // 找到新的岛,重置计数器
bfs(grid, visited, i, j, n, m);
ans = max(ans, count);
}
}
}
return ans;
}
五、孤岛的总面积
原题卡码网101 101. 孤岛的总面积
先遍历图的四周运行一次dfs,把所有不是孤岛的陆地都置为0,再遍历全图求孤岛面积
1、深度优先搜索
#include <iostream>
#include <vector>
using namespace std;
int dirs[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
int count;
void dfs(vector<vector<int>>& graph, int x, int y, int n, int m)
{
graph[x][y] = 0;
count++;
for (const auto& dir : dirs)
{
int nextX = x + dir[0];
int nextY = y + dir[1];
if (nextX >= n || nextX < 0 || nextY >= m || nextY < 0)
{
continue;
}
if (graph[nextX][nextY] == 0)
{
continue;
}
dfs(graph, nextX, nextY, n, m);
}
}
int main()
{
int N, M;
cin >> N >> M;
vector<vector<int>> graph(N, vector<int>(M, 0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
cin >> graph[i][j];
}
}
for (int i = 0; i < N; i++)
{
if (graph[i][0] == 1)
{
dfs(graph, i, 0, N, M);
}
if (graph[i][M - 1] == 1)
{
dfs(graph, i, M - 1, N, M);
}
}
for (int j = 0; j < M; j++)
{
if (graph[0][j] == 1)
{
dfs(graph, 0, j, N, M);
}
if (graph[N - 1][j] == 1)
{
dfs(graph, N - 1, j, N, M);
}
}
count = 0;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
if (graph[i][j] == 1)
{
dfs(graph, i, j, N, M);
}
}
}
cout << count << endl;
return 0;
}
2、广度优先搜索
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dirs[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
int count;
void bfs(vector<vector<int>>& graph, int x, int y, int n, int m)
{
queue<pair<int, int>> que;
que.push({ x,y });
graph[x][y] = 0;
count++;
while (!que.empty())
{
pair<int, int> curNode = que.front();
que.pop();
for (const auto& dir : dirs)
{
int nextX = curNode.first + dir[0];
int nextY = curNode.second + dir[1];
if (nextX >= n || nextX < 0 || nextY >= m || nextY < 0)
{
continue;
}
if (graph[nextX][nextY] == 0)
{
continue;
}
que.push({ nextX,nextY });
count++;
graph[nextX][nextY] = 0;
}
}
}
int main()
{
int N, M;
cin >> N >> M;
vector<vector<int>> graph(N, vector<int>(M, 0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
cin >> graph[i][j];
}
}
for (int i = 0; i < N; i++)
{
if (graph[i][0] == 1)
{
bfs(graph, i, 0, N, M);
}
if (graph[i][M - 1] == 1)
{
bfs(graph, i, M - 1, N, M);
}
}
for (int j = 0; j < M; j++)
{
if (graph[0][j] == 1)
{
bfs(graph, 0, j, N, M);
}
if (graph[N - 1][j] == 1)
{
bfs(graph, N - 1, j, N, M);
}
}
count = 0;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
if (graph[i][j] == 1)
{
bfs(graph, i, j, N, M);
}
}
}
cout << count << endl;
return 0;
}