图论(dfs深搜系列)9.23

类型一:dfs寻找独立连通块

一、统计无向图中无法互相到达的点的对数

给你一个整数 n ,表示一张无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。

思路:

首先找到独立的连通块以及该块中点的个数,一个连通块中的点和其他连通块都是无法互相到达的。所以假设一个连通块的点为x,一共的点为n;x*(n-x)/2。就是无法相互到达的点的对数

1.找到独立的连通块以及块中的个数。

如何找到独立的连通块,每次for循环,进去dfs函数,一连串的就是一个独立的连通块。

所以只需要在dfs中添加一个 记录块中的个数即可。

代码:
复制代码
class Solution {
    boolean[] visited;
    public long countPairs(int n, int[][] edges) {
        //计算出每一个连通块中的个数就OK
        int size=edges.length;
        visited=new boolean[n];
        List<List<Integer>> links=new ArrayList<>();
        for(int i=0;i<n;i++)links.add(new ArrayList<>());
        for(int i=0;i<size;i++){
            links.get(edges[i][0]).add(edges[i][1]);
            links.get(edges[i][1]).add(edges[i][0]);
        }
        //计算无法相互到达的点数
        long res=0;
        for(int i=0;i<n;i++){
            if(visited[i])continue;
            long cnt=dfs(i,links);
            res+=cnt*(n-cnt);
        }
        return res/2;
    }
    public long dfs(int current,List<List<Integer>> links){
        long count=1;
        visited[current]=true;
        for(int next:links.get(current)){
            if(!visited[next]){
                count+=dfs(next,links);
            }
        }
        return count;
    }
}

难度递增,数据结构上增加难度

二、两个城市间路径的最小分数

给你一个正整数 n ,表示总共有 n 个城市,城市从 1 到 n 编号。给你一个二维数组 roads ,其中 roads[i] = [ai, bi, distancei] 表示城市 ai 和 bi 之间有一条 双向 道路,道路距离为 distancei 。城市构成的图不一定是连通的。

两个城市之间一条路径的 分数 定义为这条路径中道路的 最小 距离。

城市 1 和城市 n 之间的所有路径的 最小 分数。

题意:

让求从城市1->n之间,所有路径的最小分数。注意:路径是可以折返的;并且题目保证从1->n之间一定有一条路。

思路:

所以这道题就让我们求,以1开始的连通块中边的最小分数。

但是难点在于,两边之间不仅仅是点的序号,还有之间的距离。

所以在使用数据结构定义邻接表的时候就要考虑清楚。

之前定义邻接表的时候是:List<List<Integer>> links;集合里面存放集合,第一个集合是所有点的邻接表;第二个集合是下标为i的点的表。但是这个长度是与下标为i的点相邻的点的个数

在这里我们要用::List<List<int\[\]>> 或者 List<int\[\]>\[\] 两种方式来定义。

代码:
复制代码
class Solution {
    boolean[] visited;
    public int minScore(int n, int[][] roads) {
        //在一个数组里面放的集合,集合里元素的类型是int[]
        visited=new boolean[n+1];
        List<int[]>[] links=new ArrayList[n+1];
        for(int i=1;i<=n;i++)links[i]=new ArrayList<>();
        //初始化邻接表
        for(int[] road:roads){
            int x=road[0];
            int y=road[1];
            int distance=road[2];
            links[x].add(new int[]{y,distance});
            links[y].add(new int[]{x,distance});
        }
        return dfs(1,links);
    }
    public int dfs(int current,List<int[]>[] links){
        visited[current]=true;
        int min=Integer.MAX_VALUE;
        for(int[] arr:links[current]){
            min=Math.min(min,arr[1]);
            if(!visited[arr[0]]){
                min=Math.min(min,dfs(arr[0],links));
            }
        }
        return min;
    }
}

三、统计完全连通分量的数量

给你一个整数 n 。现有一个包含 n 个顶点的 无向 图,顶点按从 0 到 n - 1 编号。给你一个二维整数数组 edges 其中 edges[i] = [ai, bi] 表示顶点 ai 和 bi 之间存在一条 无向 边。

完全连通分量:每个点之间都有一条边相连;所以:点*(点-1)/2==边数
思路:

判断每个连通块中边和点的数目,只要!visitednext,dfs(next,links)。进去dfs函数之后,点就+1;

复制代码
    public void dfs(int current,List<List<Integer>> links){
        visited[current]=true;
        data[0]++;
    }

在对下标为i的邻接表进行遍历的时候,有边就++;但是会多数一倍。

复制代码
    public void dfs(int current,List<List<Integer>> links){
        visited[current]=true;
        data[0]++;
        for(int next:links.get(current)){
            data[1]++;
            if(!visited[next]){
                dfs(next,links);
            }
        }
    }
代码:
复制代码
class Solution {
    boolean[] visited;
    int[] data;
    public int countCompleteComponents(int n, int[][] edges) {
        //对于每个连通分量 计算其中的节点数和边数
        List<List<Integer>> links=new ArrayList<>();
        visited=new boolean[n];
        //构建邻接表
        for(int i=0;i<n;i++)links.add(new ArrayList<>());
        for(int i=0;i<edges.length;i++){
            links.get(edges[i][0]).add(edges[i][1]);
            links.get(edges[i][1]).add(edges[i][0]);
        }
        data=new int[2];
        int res=0;
        for(int i=0;i<n;i++){
            if(!visited[i]){
                dfs(i,links);
                if(data[1]==data[0]*(data[0]-1))res++;
            }
            data[0]=0;
            data[1]=0;
        }
        return res;
    }
    public void dfs(int current,List<List<Integer>> links){
        visited[current]=true;
        data[0]++;
        for(int next:links.get(current)){
            data[1]++;
            if(!visited[next]){
                dfs(next,links);
            }
        }
    }
}
相关推荐
朝朝辞暮i1 小时前
C++ 第 31C 课:Subscriber 到底是什么
开发语言·c++·算法
Evand J2 小时前
【MATLAB例程】三维RRT+APF路径规划与AOA-TDOA融合定位算法。附代码的下载链接
算法·matlab·路径规划·rrt·tdoa·apf·aoa
海绵宝宝转agent2 小时前
leetCode100算法开源笔记分享
笔记·算法
写后端的胖头鱼3 小时前
时间复杂度 & 空间复杂度
java·数据结构·算法·时间复杂度·空间复杂度
hahaha60163 小时前
黑体轨迹和色温--光源白点
人工智能·嵌入式硬件·算法·计算机视觉
海绵宝宝转agent3 小时前
基于Redis ZSet+AOP+注解实现限流注解算法
数据库·redis·算法
All for pursuit.4 小时前
【回溯-7】494.目标和
数据结构·c++·算法·leetcode
白杨尚青4 小时前
C++入门篇(十三):vector(上)——动态数组:构造、空间增长与迭代器失效
开发语言·c++·笔记·算法·stl
Jasmine_llq4 小时前
《P17461 [GESP202609 八级] 生成树计数》
算法·栈·tarjan 算法·边双连通分量·深度优先搜索 dfs·tarjan 保存当前路径节点·模乘法
Jasmine_llq4 小时前
《P17462 [GESP202609 八级] 末班车》
算法·dijkstra 算法·最大化版本,求最长可行值·建反向图(逆图 / 反转边)·多源 dijkstra 思想·对每个终点单独跑一遍djst·离线预处理 + 在线查询