当前位置:网站首页>统计无向图中无法互相到达点对数[经典建邻接表+DFS统计 -> 并查集优化][并查集手册/写的详细]
统计无向图中无法互相到达点对数[经典建邻接表+DFS统计 -> 并查集优化][并查集手册/写的详细]
2022-06-27 00:08:00 【REN_林森】
经典建邻接表+DFS统计 -> 并查集优化
前言
给定节点和边(节点对),求关于连通分量及其变种。第一想法都是根据节点和节点对(边)来建立邻接矩阵,在DFS做事。
但还有一种和连通分量紧密相关的思想,并查集,它不建立完整的图,但能做相应的事,所以运行时间短。
它将原有的图,从中选出一个节点作为根节点,所有直接/间接相连的节点都作为子节点,能解很多连通分量/连通分量变种问题。
并查集除上述优点外,我感觉它的数组hash比hashMap快,毕竟数组为JVM层面,且连续内层分配,比API快。
一、统计无向图中无法互相到达点对数


二、经典建邻接表+DFS统计 -> 并查集优化
1、经典建邻接表+DFS统计
public class CountPairs {
public long countPairs(int n, int[][] edges) {
// 加入所有节点。
for (int i = 0; i < n; i++) addNode(i);
for (int[] edge : edges) addEdge(edge[0], edge[1]);
List<Long> arr = new ArrayList<>();
for (int i = 0; i < n; i++) if (graph.containsKey(i)) arr.add(dfs(i));
//
long[] prefix = new long[arr.size()];
long sum = 0, ans = 0;
int idx = 0;
for (long i : arr) prefix[idx++] = (sum += i);
for (int i = 0; i < arr.size() - 1; i++) ans += arr.get(i) * (prefix[arr.size() - 1] - prefix[i]);
return ans;
}
private long dfs(int n) {
long rs = 1;
Set<Integer> next = graph.get(n);
if (next == null) return rs;
graph.remove(n);
for (Integer i : next) {
if (graph.containsKey(i)) rs += dfs(i);
}
return rs;
}
private void addEdge(int a, int b) {
addNode(a);
addNode(b);
graph.get(a).add(b);
graph.get(b).add(a);
}
private void addNode(int b) {
if (!graph.containsKey(b)) graph.put(b, new HashSet<>());
}
Map<Integer, Set<Integer>> graph = new HashMap<>();
}
2、并查集优化
// 练习哈并查集,它是关于连通分量的利器。
class CountPairs2 {
public long countPairs(int n, int[][] edges) {
// 并查集标准第一步:初始化。
int[] father = new int[n];
Arrays.fill(father, -1);
// 并查集标准第二步:union
cnt = n;// 这里想统计连通分量个数,方便等会统计每个连通分量的节点数,可以用到数组,而不是可扩容的list.| 也可直接list
for (int[] edge : edges) union(father, edge[0], edge[1]);
// 非特定逻辑,具体需求具体写。
// 统计每个连通分量节点数。
int[] arr = new int[cnt];
cnt = 0;
for (int f : father) if (f < 0) arr[cnt++] = -f;
// 非特定逻辑,具体需求具体写。
// 得到不同连通分量的节点数,利用前缀和,空间换时间。
long[] prefix = new long[arr.length];
long sum = 0;
cnt = 0;
for (int a : arr) prefix[cnt++] = (sum += a);
// 得到结果
long ans = 0;
for (int i = 0; i < arr.length - 1; i++) ans += arr[i] * (prefix[prefix.length - 1] - prefix[i]);
return ans;
}
int cnt = 0;// 连通分量个数。
private void union(int[] father, int m, int n) {
// 并查集标准第三步:findFather
int r1 = findFather(father, m);
int r2 = findFather(father, n);
// 非同一逻辑,根据实际情况来写。
if (r1 != r2) {
// 合并两者,就将一个作为根,得到其整个树的节点数,这里负数表示。
father[r1] += father[r2];
// 并把另一个作为子树,并把其根节点修改。
father[r2] = r1;
// 可选操作,当用list时,则不必。
--cnt;
}
}
private int findFather(int[] father, int r) {
// 一路返回根,并把根作为路径上每个节点的根.
// 体现在 if (father[r] != r) father[r] = findFather(father, father[r]); return father[r];这将把有深度的树平铺起来。
// 但是这里不行,因为根节点的值不是等于其下标,是负数,需要统计节点个数。
// 这里需要一改传统做法,要灵活变通。
// 若该节点是根
if (father[r] < 0) return r;
return father[r] = findFather(father, father[r]);
}
}
总结
1)经典邻接表建立 + 在dfs遍历(图操作的基础)做各自事。
2)并查集将图的形状改掉,但不影响解题,则它降低的运行时间就变成了优点。
3)并查集除上述优点外,我感觉它的数组hash比hashMap快,毕竟数组为JVM层面,且连续内层分配,比API快。
4)并查集经典三步,每步都可因具体需求,而灵活变通写法。具体三步为:初始化数组father[size]{}(数组hash非常nice)、union(int[],int,int)联结两节点、findFather(int[],int)寻找根节点。
参考文献
边栏推荐
- 如何写好测试用例以及go单元测试工具testify简单介绍
- [vscade] preview MD file
- Common techniques of email attachment phishing
- 2022 Health Expo, Shandong health care exhibition, postpartum health and sleep health exhibition
- 07 | 工作流设计:如何设计合理的多人开发模式?
- Competition Registration | one of the key ai+ scientific computing competitions - China open source scientific software creativity competition, competing for 100000 bonus!
- 目标追踪拍摄?目标遮挡拍摄?拥有19亿安装量的花瓣app,究竟有什么别出心裁的功能如此吸引用户?
- Cve-2022-30190 follina office rce analysis [attached with customized word template POC]
- In the Internet industry, there are many certificates with high gold content. How many do you have?
- Pinpoint attackers with burp
猜你喜欢

其他服务注册与发现

When transformer encounters partial differential equation solution

How to easily describe the process of machine learning?

万字详解-MindArmour 小白教程!

大赛报名 | AI+科学计算重点赛事之一——中国开源科学软件创意大赛,角逐十万奖金!

泰国安全又划算的支付方式

【Vscode】预览md文件

CPU exception handling

Using physical information neural network to solve hydrodynamics equations

Technical dry goods | what is a big model? Oversized model? Foundation Model?
随机推荐
No clue about complex data?
Your connection is not private
The fourth bullet of redis interview eight part essay (end)
Oracle database basics concepts
matlab数据类型 —— 字符型
消息队列简介
安利!如何提优质的ISSUE?学霸是这样写的!
巧记大小端字节序
[vscade] preview MD file
An article takes you to learn container escape
Batch generate folders based on file names
Moher College - SQL injection vulnerability test (error reporting and blind note)
Big guys talk about the experience sharing of the operation of the cutting-edge mindspore open source community. Come up with a small notebook!
Redis detailed tutorial
Technical dry goods | top speed, top intelligence and minimalist mindspore Lite: help Huawei watch become more intelligent
05 | 規範設計(下):commit 信息風格迥异、難以閱讀,如何規範?
The [MySQL] time field is set to the current time by default
数字格式化的 js 库
国产框架MindSpore联合山水自然保护中心,寻找、保护「中华水塔」中的宝藏生命
Intrusion trace cleaning