图论基本概念
图论是研究图(Graph)的数学理论,图由**顶点(Vertex)和边(Edge)**组成,用于表示对象及其关系。
- 无向图:边无方向,用无序对 (u, v) 表示。
- 有向图:边有方向,用有序对 (u \\to v) 表示。
- 权重图:边附带权值,常用于路径优化问题。
- 常见术语:度(Degree)、路径(Path)、环(Cycle)、连通性(Connectedness)。
图的存储方式(C++实现)
邻接矩阵
适用于稠密图,空间复杂度 O(V\^2)。
cpp
const int MAX_V = 100;
int adjMatrix[MAX_V][MAX_V]; // 初始化为0或INF
邻接表
适用于稀疏图,空间复杂度 O(V + E)。
cpp
#include <vector>
vector<int> adjList[MAX_V]; // 无权重
vector<pair<int, int>> weightedAdjList[MAX_V]; // 带权重
图遍历算法
深度优先搜索(DFS)
递归或栈实现,用于连通性检测、拓扑排序等。
cpp
bool visited[MAX_V];
void dfs(int u) {
visited[u] = true;
for (int v : adjList[u]) {
if (!visited[v]) dfs(v);
}
}
广度优先搜索(BFS)
队列实现,用于最短路径(无权图)。
cpp
queue<int> q;
bool visited[MAX_V];
void bfs(int start) {
q.push(start);
visited[start] = true;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : adjList[u]) {
if (!visited[v]) {
visited[v] = true;
q.push(v);
}
}
}
}
最短路径算法
Dijkstra算法
适用于非负权图,时间复杂度 O((V + E) \\log V)。
cpp
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
vector<int> dist(MAX_V, INF);
void dijkstra(int start) {
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] : weightedAdjList[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.push({dist[v], v});
}
}
}
}
Floyd-Warshall算法
动态规划实现,适用于所有节点对的最短路径,时间复杂度 O(V\^3)。
cpp
int dist[MAX_V][MAX_V];
void floydWarshall(int V) {
for (int k = 0; k < V; ++k)
for (int i = 0; i < V; ++i)
for (int j = 0; j < V; ++j)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
最小生成树(MST)
Kruskal算法
基于并查集,时间复杂度 O(E \\log E)。
cpp
struct Edge { int u, v, w; };
vector<Edge> edges;
int parent[MAX_V];
int find(int u) { return parent[u] == u ? u : parent[u] = find(parent[u]); }
int kruskal() {
sort(edges.begin(), edges.end(), [](Edge a, Edge b) { return a.w < b.w; });
for (int i = 0; i < MAX_V; ++i) parent[i] = i;
int total = 0;
for (Edge e : edges) {
int pu = find(e.u), pv = find(e.v);
if (pu != pv) {
parent[pu] = pv;
total += e.w;
}
}
return total;
}
Prim算法
优先队列实现,时间复杂度 O(E \\log V)。
cpp
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
bool inMST[MAX_V];
int prim() {
pq.push({0, 0});
int total = 0;
while (!pq.empty()) {
auto [w, u] = pq.top(); pq.pop();
if (inMST[u]) continue;
inMST[u] = true;
total += w;
for (auto [v, weight] : weightedAdjList[u]) {
if (!inMST[v]) pq.push({weight, v});
}
}
return total;
}
拓扑排序
适用于有向无环图(DAG),基于DFS或BFS(Kahn算法)。
cpp
vector<int> topoSort(int V) {
vector<int> inDegree(V, 0), result;
for (int u = 0; u < V; ++u)
for (int v : adjList[u]) inDegree[v]++;
queue<int> q;
for (int u = 0; u < V; ++u)
if (inDegree[u] == 0) q.push(u);
while (!q.empty()) {
int u = q.front(); q.pop();
result.push_back(u);
for (int v : adjList[u]) {
if (--inDegree[v] == 0) q.push(v);
}
}
return result.size() == V ? result : vector<int>(); // 检查环
}
关键考点总结
- 基础概念:图的分类、术语(度、连通分量等)。
- 存储与遍历:邻接表/矩阵的选择,DFS/BFS的应用场景。
- 算法实现:Dijkstra、Floyd、Kruskal、Prim的代码模板。
- 拓扑排序:DAG的判定与排序方法。
- 复杂度分析:各算法的时间/空间复杂度比较。
建议结合实际问题(如LeetCode、OJ题目)练习代码实现。