C++图论算法实战精解
图论基础理论与实际应用详解(C++实现)
一、基本概念
图 $G$ 由顶点集 $V$ 和边集 $E$ 构成,记为 $G=(V,E)$。
- 有向图:边有方向,$E \subseteq V \times V$
- 无向图:边无方向,$E$ 为无序对集合
- 权重图:边附加权值函数 $w: E \to \mathbb{R}$
存储结构:
- 邻接矩阵(稠密图适用):
const int MAXN = 1000;
int graph[MAXN][MAXN]; // 权重存于矩阵
- 邻接表(稀疏图高效):
#include <vector>
using namespace std;
struct Edge {
int to;
int weight;
};
vector<vector<Edge>> adjList; // adjList[i]存储顶点i的邻接边
二、图的遍历算法
深度优先搜索(DFS)
vector<bool> visited;
void dfs(int u) {
visited[u] = true;
for (auto& edge : adjList[u]) {
if (!visited[edge.to]) {
dfs(edge.to);
}
}
}
应用场景:连通分量检测、拓扑排序、回溯法
广度优先搜索(BFS)
#include <queue>
void bfs(int start) {
queue<int> q;
q.push(start);
visited[start] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (auto& edge : adjList[u]) {
if (!visited[edge.to]) {
visited[edge.to] = true;
q.push(edge.to);
}
}
}
}
应用场景:最短路径(无权图)、层级遍历
三、经典问题与算法
1. 最短路径(Dijkstra算法)
核心思想:贪心策略,适用于非负权图
$$d[v] = \min(d[u] + w(u,v))$$
#include <queue>
#include <climits>
vector<int> dijkstra(int src, int n) {
vector<int> dist(n, INT_MAX);
dist[src] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, src});
while (!pq.empty()) {
auto [d, u] = pq.top();
pq.pop();
if (d != dist[u]) continue; // 旧数据跳过
for (auto& edge : adjList[u]) {
int newDist = d + edge.weight;
if (newDist < dist[edge.to]) {
dist[edge.to] = newDist;
pq.push({newDist, edge.to});
}
}
}
return dist;
}
2. 拓扑排序(Kahn算法)
适用条件:有向无环图(DAG)
$$ \text{入度} \operatorname{deg}^{-}(v) = 0 \implies \text{可移除} $$
vector<int> topologicalSort(int n) {
vector<int> indegree(n, 0);
vector<int> result;
queue<int> q;
// 计算入度
for (int u = 0; u < n; u++)
for (auto& edge : adjList[u])
indegree[edge.to]++;
// 入度为0入队
for (int i = 0; i < n; i++)
if (indegree[i] == 0) q.push(i);
while (!q.empty()) {
int u = q.front();
q.pop();
result.push_back(u);
for (auto& edge : adjList[u]) {
if (--indegree[edge.to] == 0)
q.push(edge.to);
}
}
return result.size() == n ? result : vector<int>{}; // 判断环
}
3. 最小生成树(Prim算法)
目标:连接所有顶点的最小权重边集
$$ T \subseteq E, \quad \min \sum_{e \in T} w(e) $$
int prim(int n) {
vector<bool> visited(n, false);
vector<int> minDist(n, INT_MAX);
minDist[0] = 0;
int total = 0;
for (int i = 0; i < n; i++) {
int u = -1;
for (int j = 0; j < n; j++) // 选最小未访问点
if (!visited[j] && (u == -1 || minDist[j] < minDist[u]))
u = j;
if (minDist[u] == INT_MAX) return -1; // 不连通
visited[u] = true;
total += minDist[u];
for (auto& edge : adjList[u])
if (edge.weight < minDist[edge.to])
minDist[edge.to] = edge.weight;
}
return total;
}
四、实际应用场景
-
路径规划
- 导航系统(Dijkstra/A*算法)
- 物流配送(带时间窗的最短路径)
-
依赖分析
- 编译顺序(拓扑排序)
- 任务调度(关键路径法)
-
网络优化
- 通信网布线(最小生成树)
- 最大流问题(Ford-Fulkerson算法)
五、复杂问题扩展
- 负权处理:Bellman-Ford算法(动态规划)
- 全源最短路径:Floyd-Warshall算法(三重循环)
- 图的连通性:Tarjan强连通分量算法
提示:实际编码需处理边界条件(如不连通图、自环边),建议使用C++ STL的
priority_queue优化Dijkstra,时间复杂度降至 $O(|E|\log|V|)$。
© 版权声明
文章版权归作者所有,未经允许请勿转载。