图论03-【无权无向】-图的深度优先DFS遍历-路径问题/检测环/二分图

文章目录

  • [1. 代码仓库](#1. 代码仓库)
  • [2. 单源路径](#2. 单源路径)
    • [2.1 思路](#2.1 思路)
    • [2.2 主要代码](#2.2 主要代码)
  • [3. 所有点对路径](#3. 所有点对路径)
    • [3.1 思路](#3.1 思路)
    • [3.2 主要代码](#3.2 主要代码)
  • [4. 路径问题的优化-提前结束递归](#4. 路径问题的优化-提前结束递归)
    • [4.1 思路](#4.1 思路)
    • [4.2 主要代码](#4.2 主要代码)
  • [5. 检测环](#5. 检测环)
    • [5.1 思路](#5.1 思路)
    • [5.2 主要代码](#5.2 主要代码)
  • [6. 二分图](#6. 二分图)
    • [6.1 思路](#6.1 思路)
    • [6.2 主要代码](#6.2 主要代码)
      • [6.2.1 遍历每个联通分量](#6.2.1 遍历每个联通分量)
      • [6.2.2 递归判断相邻两点的颜色是否一致](#6.2.2 递归判断相邻两点的颜色是否一致)

1. 代码仓库

https://github.com/Chufeng-Jiang/Graph-Theory

2. 单源路径

2.1 思路

  1. 构造visited数组和pre数组
    1.1 visited数组记录当前节点是否访问过
    也可以不使用visited数组,pre数组全部初始化为-1,联通的顶点对应的pre数组的值为前一个节点,pre数组中值为-1的都是不连通的顶点。
    1.2 pre数组记录当前节点的前一个节点
  2. 使用pre数组对终点进行反推回源点,并记录
  3. 将终点到原点的路径,反序输出

2.2 主要代码

cpp 复制代码
   public SingleSourcePath(Graph G, int s){ //单源路径,要把源s传进来,而且只考虑与s连通的顶点,不连通的不考虑

        G.validateVertex(s);

        this.G = G;
        this.s = s;
        visited = new boolean[G.V()];
        pre = new int[G.V()];

        dfs(s, s);
    }

    private void dfs(int v, int parent){ //参数一:当前顶点; 参数二:上一个顶点

        visited[v] = true;
        pre[v] = parent;

        for(int w: G.adj(v)) //跟v相邻的所有顶点,相当于v是源,遍历与当前顶点相邻的所有点
            if(!visited[w])
                dfs(w, v); //(顶点,源)
    }
    
     public Iterable<Integer> path(int t){ //从源到t的路径

	     ArrayList<Integer> res = new ArrayList<Integer>();
	     if(!isConnectedTo(t)) return res;	
	     int cur = t; // 从t往回找
	     
	     while(cur != s){
	         res.add(cur); //添加当前节点(循环内不包含源)
	         cur = pre[cur]; //pre[cur]的值是cur的上一个节点
	     }
	     
	     res.add(s); //添加源
	     Collections.reverse(res);
	     return res;
 }

3. 所有点对路径

3.1 思路

对所有顶点进行遍历,创建每一个点的单源路径数组。

3.2 主要代码

cpp 复制代码
public AllPairsPath(Graph G){
    this.G = G;
    paths = new SingleSourcePath[G.V()];
    for(int v = 0; v < G.V(); v ++)
        paths[v] = new SingleSourcePath(G, v);
}

4. 路径问题的优化-提前结束递归

4.1 思路

在填充visited和pre数组的时候,如果遇到了目标节点,直接结束。剩下的节点不进行处理。

if(v == t) return true; //程序出口,当到达t顶点时,返回true提前结束递归,而不仅仅是返回return

4.2 主要代码

cpp 复制代码
    private boolean dfs(int v, int parent){

        visited[v] = true;
        pre[v] = parent;

        if(v == t) return true; //程序出口,当到达t顶点时,返回true提前结束递归,而不仅仅是返回return

        for(int w: G.adj(v)) //遍历与v相邻的顶点
            if(!visited[w]) //如果相邻的顶点没有被访问过
                if(dfs(w, v)) //递归遍历相邻的顶点,如果到达 v==t,则值为true
                    return true; //提前返回true

        return false; // 转一圈没法达到t,就可以返回false
    }

5. 检测环

5.1 思路

从某一点v出发,找到了点w,w被访问过,并且w不是v的前一个节点

5.2 主要代码

cpp 复制代码
public CycleDetection(Graph G){
    this.G = G;
    visited = new boolean[G.V()];

    //要对所有的连通分量进行环检测
    for(int v = 0; v < G.V(); v ++)
        if(!visited[v])  //如果没有访问过
            if(dfs(v, v)){ //则进行深度搜索,如果深度搜索出来的是true,说明有环,则进入循环break
                hasCycle = true;
                break;
            }
}

    
private boolean dfs(int v, int parent){
    visited[v] = true;

    for(int w: G.adj(v))
        if(!visited[w]){ //case1:如果w没有被访问过
            if(dfs(w, v)) //如果dfs返回true,则说明有环。因为dfs有环才会返回true,那么进入if选择语句return true提前结束
                return true;
        }
        else if(w != parent) // case2:从v出发,找到了w,w还被访问过,并且w不是v的前一个节点
            return true; // 此时找到了环

    //其他的情况,找一圈没有找到环,返回false
    return false;
}

6. 二分图

6.1 思路

二分图可以通过染色过程把顶点区分开,
[-1:顶点还没染色]
[0:一种颜色]
[1:另外一种颜色]

6.2 主要代码

6.2.1 遍历每个联通分量

  1. dfs(v, 0) 返回true代表相连的两点颜色不一样,暂未出现矛盾;
  2. dfs(v, 0) 返回false代表相连的两点颜色一样,不符合二分图的定义,因此进入if语句块,设置isBipartite = false;并且提前结束循环。
cpp 复制代码
for(int v = 0; v < G.V(); v ++)
    if(!visited[v]) //如果没有被访问
    // 起始的时候把v统一染成0色,如果dfs返回的false,进入下面结构体,否则跳出执行v++
        if(!dfs(v, 0)){ 
            isBipartite = false; // 检测出错了,就设置成false
            break; // 后续的循环就不需要进行了
        }

6.2.2 递归判断相邻两点的颜色是否一致

cpp 复制代码
private boolean dfs(int v, int color){  //参数一:顶点   参数二:颜色
    visited[v] = true;
    colors[v] = color;

    //依次判断相邻顶点w的颜色
    for(int w: G.adj(v))
        if(!visited[w]){ //如果w没有被访问过,则进入判断
            if(!dfs(w, 1 - color)) //如果v的颜色是0,那么w的颜色应该是1。如果v的颜色是1,那么w的颜色应该是0.
                return false; //如果相邻的两个顶点颜色一样,那么就不是二分图
        }
        else if(colors[w] == colors[v]) //如果相邻的两个顶点颜色一样,那么就不是二分图
            return false;

        return true;
}
相关推荐
莫叫石榴姐33 分钟前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
茶猫_2 小时前
力扣面试题 - 25 二进制数转字符串
c语言·算法·leetcode·职场和发展
肥猪猪爸4 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
readmancynn4 小时前
二分基本实现
数据结构·算法
萝卜兽编程4 小时前
优先级队列
c++·算法
盼海4 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步4 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln5 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
芜湖_5 小时前
【山大909算法题】2014-T1
算法·c·单链表
珹洺5 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode