09.01_基础图论

基础图论

问题描述

基础图论处理图的遍历和基本性质,包括DFS、BFS、拓扑排序和强连通分量等问题。

深度优先搜索

算法思想

  1. 沿着一条路径尽可能深入
  2. 使用栈或递归实现
  3. 适用于路径查找和连通性判断
  4. 时间复杂度

代码实现

class Solution {
public:
    vector<vector<int>> adj;  // 邻接表
    vector<bool> visited;     // 访问标记
    
    void dfs(int v) {
        visited[v] = true;
        for (int u : adj[v]) {
            if (!visited[u]) {
                dfs(u);
            }
        }
    }
    
    // 检测环
    bool hasCycle(int v, int parent) {
        visited[v] = true;
        for (int u : adj[v]) {
            if (!visited[u]) {
                if (hasCycle(u, v)) return true;
            } else if (u != parent) {
                return true;
            }
        }
        return false;
    }
};
class Solution {
    private List<List<Integer>> adj;  // 邻接表
    private boolean[] visited;         // 访问标记
    
    public void dfs(int v) {
        visited[v] = true;
        for (int u : adj.get(v)) {
            if (!visited[u]) {
                dfs(u);
            }
        }
    }
    
    // 检测环
    public boolean hasCycle(int v, int parent) {
        visited[v] = true;
        for (int u : adj.get(v)) {
            if (!visited[u]) {
                if (hasCycle(u, v)) return true;
            } else if (u != parent) {
                return true;
            }
        }
        return false;
    }
}
class Solution:
    def __init__(self):
        self.adj = []      # 邻接表
        self.visited = []  # 访问标记
    
    def dfs(self, v: int) -> None:
        self.visited[v] = True
        for u in self.adj[v]:
            if not self.visited[u]:
                self.dfs(u)
    
    # 检测环
    def hasCycle(self, v: int, parent: int) -> bool:
        self.visited[v] = True
        for u in self.adj[v]:
            if not self.visited[u]:
                if self.hasCycle(u, v):
                    return True
            elif u != parent:
                return True
        return False

广度优先搜索

算法思想

  1. 逐层遍历图中节点
  2. 使用队列实现
  3. 适用于最短路径和层次遍历
  4. 时间复杂度

代码实现

class Solution {
public:
    vector<vector<int>> adj;  // 邻接表
    vector<bool> visited;     // 访问标记
    
    void bfs(int start) {
        queue<int> q;
        q.push(start);
        visited[start] = true;
        
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            
            for (int u : adj[v]) {
                if (!visited[u]) {
                    visited[u] = true;
                    q.push(u);
                }
            }
        }
    }
};
class Solution {
    private List<List<Integer>> adj;  // 邻接表
    private boolean[] visited;         // 访问标记
    
    public void bfs(int start) {
        Queue<Integer> q = new LinkedList<>();
        q.offer(start);
        visited[start] = true;
        
        while (!q.isEmpty()) {
            int v = q.poll();
            
            for (int u : adj.get(v)) {
                if (!visited[u]) {
                    visited[u] = true;
                    q.offer(u);
                }
            }
        }
    }
}
class Solution:
    def bfs(self, start: int) -> None:
        q = deque([start])
        self.visited[start] = True
        
        while q:
            v = q.popleft()
            
            for u in self.adj[v]:
                if not self.visited[u]:
                    self.visited[u] = True
                    q.append(u)

时间复杂度分析

算法 时间复杂度 空间复杂度
DFS
BFS
拓扑排序
强连通分量

应用场景

  1. 路径查找
  2. 连通性判断
  3. 环路检测
  4. 拓扑排序
  5. 二分图判定

注意事项

  1. 图的表示方式
  2. 访问标记的重置
  3. 递归栈的深度
  4. 连通性的处理
  5. 环路的判断

常见变形

  1. 拓扑排序
class Solution {
public:
    vector<int> topologicalSort(vector<vector<int>>& adj) {
        int n = adj.size();
        vector<int> indegree(n);
        vector<int> result;
        
        // 计算入度
        for (const auto& edges : adj) {
            for (int v : edges) {
                indegree[v]++;
            }
        }
        
        // BFS
        queue<int> q;
        for (int i = 0; i < n; i++) {
            if (indegree[i] == 0) {
                q.push(i);
            }
        }
        
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            result.push_back(v);
            
            for (int u : adj[v]) {
                if (--indegree[u] == 0) {
                    q.push(u);
                }
            }
        }
        
        return result.size() == n ? result : vector<int>();
    }
};
class Solution {
    public List<Integer> topologicalSort(List<List<Integer>> adj) {
        int n = adj.size();
        int[] indegree = new int[n];
        List<Integer> result = new ArrayList<>();
        
        // 计算入度
        for (List<Integer> edges : adj) {
            for (int v : edges) {
                indegree[v]++;
            }
        }
        
        // BFS
        Queue<Integer> q = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (indegree[i] == 0) {
                q.offer(i);
            }
        }
        
        while (!q.isEmpty()) {
            int v = q.poll();
            result.add(v);
            
            for (int u : adj.get(v)) {
                if (--indegree[u] == 0) {
                    q.offer(u);
                }
            }
        }
        
        return result.size() == n ? result : new ArrayList<>();
    }
}
class Solution:
    def topologicalSort(self, adj: List[List[int]]) -> List[int]:
        n = len(adj)
        indegree = [0] * n
        result = []
        
        # 计算入度
        for edges in adj:
            for v in edges:
                indegree[v] += 1
        
        # BFS
        q = deque([i for i in range(n) if indegree[i] == 0])
        
        while q:
            v = q.popleft()
            result.append(v)
            
            for u in adj[v]:
                indegree[u] -= 1
                if indegree[u] == 0:
                    q.append(u)
        
        return result if len(result) == n else []
  1. 二分图判定
class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<int> color(n, -1);
        
        for (int i = 0; i < n; i++) {
            if (color[i] == -1) {
                if (!dfs(graph, i, 0, color)) {
                    return false;
                }
            }
        }
        return true;
    }
    
private:
    bool dfs(vector<vector<int>>& graph, int v, int c, vector<int>& color) {
        color[v] = c;
        for (int u : graph[v]) {
            if (color[u] == -1) {
                if (!dfs(graph, u, c ^ 1, color)) {
                    return false;
                }
            } else if (color[u] == c) {
                return false;
            }
        }
        return true;
    }
};
class Solution {
    public boolean isBipartite(List<List<Integer>> graph) {
        int n = graph.size();
        int[] color = new int[n];
        Arrays.fill(color, -1);
        
        for (int i = 0; i < n; i++) {
            if (color[i] == -1) {
                if (!dfs(graph, i, 0, color)) {
                    return false;
                }
            }
        }
        return true;
    }
    
    private boolean dfs(List<List<Integer>> graph, int v, int c, int[] color) {
        color[v] = c;
        for (int u : graph.get(v)) {
            if (color[u] == -1) {
                if (!dfs(graph, u, c ^ 1, color)) {
                    return false;
                }
            } else if (color[u] == c) {
                return false;
            }
        }
        return true;
    }
}
class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        n = len(graph)
        color = [-1] * n
        
        def dfs(v: int, c: int) -> bool:
            color[v] = c
            for u in graph[v]:
                if color[u] == -1:
                    if not dfs(u, c ^ 1):
                        return False
                elif color[u] == c:
                    return False
            return True
        
        for i in range(n):
            if color[i] == -1:
                if not dfs(i, 0):
                    return False
        return True

经典例题

  1. 【模板】拓扑排序
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论

相关推荐

不愿透露姓名的神秘牛友
今天 16:32
点赞 评论 收藏
分享
FieldMatching:看成了猪头顾问,不好意思
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务