Appearance
L7_04 图论算法
一、图的泛洪算法(Flood Fill)
1.1 泛洪算法概述
泛洪算法(Flood Fill)是一种从起始点开始,向四周扩散遍历所有连通节点的算法。
1.2 四方向泛洪填充
cpp
void floodFill(vector<vector<int>>& grid, int i, int j, int oldColor, int newColor) {
if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) {
return;
}
if (grid[i][j] != oldColor) {
return;
}
grid[i][j] = newColor;
floodFill(grid, i + 1, j, oldColor, newColor);
floodFill(grid, i - 1, j, oldColor, newColor);
floodFill(grid, i, j + 1, oldColor, newColor);
floodFill(grid, i, j - 1, oldColor, newColor);
}1.3 八方向泛洪填充
cpp
void floodFill8(vector<vector<int>>& grid, int i, int j, int oldColor, int newColor) {
if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) {
return;
}
if (grid[i][j] != oldColor) {
return;
}
grid[i][j] = newColor;
// 八个方向
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (dx != 0 || dy != 0) {
floodFill8(grid, i + dx, j + dy, oldColor, newColor);
}
}
}
}1.4 BFS 实现泛洪填充
cpp
void floodFillBFS(vector<vector<int>>& grid, int startI, int startJ, int newColor) {
int oldColor = grid[startI][startJ];
if (oldColor == newColor) return;
int rows = grid.size();
int cols = grid[0].size();
queue<pair<int, int>> q;
q.push({startI, startJ});
grid[startI][startJ] = newColor;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
while (!q.empty()) {
auto [i, j] = q.front();
q.pop();
for (int k = 0; k < 4; k++) {
int ni = i + dx[k];
int nj = j + dy[k];
if (ni >= 0 && ni < rows && nj >= 0 && nj < cols && grid[ni][nj] == oldColor) {
grid[ni][nj] = newColor;
q.push({ni, nj});
}
}
}
}二、连通分量
2.1 无向图的连通分量
cpp
void dfsCC(int node, vector<bool>& visited, const vector<vector<int>>& graph) {
visited[node] = true;
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
dfsCC(neighbor, visited, graph);
}
}
}
int countConnectedComponents(const vector<vector<int>>& graph) {
int n = graph.size();
vector<bool> visited(n, false);
int count = 0;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
count++;
dfsCC(i, visited, graph);
}
}
return count;
}2.2 强连通分量(Kosaraju算法)
cpp
void dfs1(int node, vector<bool>& visited, const vector<vector<int>>& graph, vector<int>& order) {
visited[node] = true;
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
dfs1(neighbor, visited, graph, order);
}
}
order.push_back(node);
}
void dfs2(int node, vector<bool>& visited, const vector<vector<int>>& reversedGraph, vector<int>& component) {
visited[node] = true;
component.push_back(node);
for (int neighbor : reversedGraph[node]) {
if (!visited[neighbor]) {
dfs2(neighbor, visited, reversedGraph, component);
}
}
}
vector<vector<int>> kosaraju(const vector<vector<int>>& graph) {
int n = graph.size();
vector<bool> visited(n, false);
vector<int> order;
// 第一次DFS
for (int i = 0; i < n; i++) {
if (!visited[i]) {
dfs1(i, visited, graph, order);
}
}
// 构建反向图
vector<vector<int>> reversedGraph(n);
for (int i = 0; i < n; i++) {
for (int j : graph[i]) {
reversedGraph[j].push_back(i);
}
}
// 第二次DFS
fill(visited.begin(), visited.end(), false);
reverse(order.begin(), order.end());
vector<vector<int>> components;
for (int node : order) {
if (!visited[node]) {
vector<int> component;
dfs2(node, visited, reversedGraph, component);
components.push_back(component);
}
}
return components;
}三、最小生成树
3.1 Kruskal算法
cpp
struct Edge {
int u, v, weight;
bool operator<(const Edge& other) const {
return weight < other.weight;
}
};
vector<int> parent;
vector<int> rank_;
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
if (rank_[x] < rank_[y]) {
parent[x] = y;
} else {
parent[y] = x;
if (rank_[x] == rank_[y]) {
rank_[x]++;
}
}
}
int kruskal(int n, vector<Edge>& edges) {
sort(edges.begin(), edges.end());
parent.resize(n);
rank_.resize(n, 0);
for (int i = 0; i < n; i++) {
parent[i] = i;
}
int totalWeight = 0;
int edgesUsed = 0;
for (const Edge& e : edges) {
if (find(e.u) != find(e.v)) {
unite(e.u, e.v);
totalWeight += e.weight;
edgesUsed++;
if (edgesUsed == n - 1) break;
}
}
return totalWeight;
}3.2 Prim算法
cpp
int prim(int n, const vector<vector<pair<int, int>>>& graph) {
vector<bool> inMST(n, false);
vector<int> key(n, INT_MAX);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
key[0] = 0;
pq.push({0, 0});
int totalWeight = 0;
while (!pq.empty()) {
auto [weight, u] = pq.top();
pq.pop();
if (inMST[u]) continue;
inMST[u] = true;
totalWeight += weight;
for (auto [v, w] : graph[u]) {
if (!inMST[v] && w < key[v]) {
key[v] = w;
pq.push({w, v});
}
}
}
return totalWeight;
}四、最短路径
4.1 Dijkstra算法
cpp
vector<int> dijkstra(int start, const vector<vector<pair<int, int>>>& graph) {
int n = graph.size();
vector<int> dist(n, INT_MAX);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
dist[start] = 0;
pq.push({0, start});
while (!pq.empty()) {
auto [d, u] = pq.top();
pq.pop();
if (d > dist[u]) continue;
for (auto [v, w] : graph[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.push({dist[v], v});
}
}
}
return dist;
}4.2 Bellman-Ford算法
cpp
vector<int> bellmanFord(int start, int n, const vector<tuple<int, int, int>>& edges) {
vector<int> dist(n, INT_MAX);
dist[start] = 0;
for (int i = 0; i < n - 1; i++) {
for (auto [u, v, w] : edges) {
if (dist[u] != INT_MAX && dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
}
}
}
// 检测负权环
for (auto [u, v, w] : edges) {
if (dist[u] != INT_MAX && dist[v] > dist[u] + w) {
// 存在负权环
}
}
return dist;
}4.3 Floyd-Warshall算法
cpp
vector<vector<int>> floydWarshall(const vector<vector<int>>& graph) {
int n = graph.size();
vector<vector<int>> dist = graph;
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX) {
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
}
return dist;
}五、图论算法对比
| 算法 | 用途 | 时间复杂度 | 适用场景 |
|---|---|---|---|
| Flood Fill | 连通区域标记 | O(n*m) | 图像分割、区域标记 |
| Kruskal | 最小生成树 | O(E log E) | 稀疏图 |
| Prim | 最小生成树 | O(E + V log V) | 稠密图 |
| Dijkstra | 最短路径 | O((V + E) log V) | 非负权图 |
| Bellman-Ford | 最短路径 | O(VE) | 含负权边图 |
| Floyd-Warshall | 所有点对最短路径 | O(V³) | 稠密图、小规模图 |
