三元环计数

博客探讨了如何计算图中三元团(三元环)的数量,提出了一种O(mm)时间复杂度的算法。算法通过让度数高的点连接度数低的点,枚举节点及其邻居来避免重复计算,确保图是一个有向无环图(DAG)。

三元环计数

就是考试的时候整了一个这个科技,我没想出来,然后无了…

具体来说就是计算图中三元团的个数。

有一个 O(mm)O(m\sqrt m)O(mm ) 的算法:

  • 让度数大的点连接度数小的点。
  • 枚举每个点并将其相邻的点记录匹配点为当前点 iii
  • 枚举当前点邻居的邻居,看匹配点是否是点 iii

每个三元团只会被计算一次。


分析一下复杂度:

每个点的入度度数最大是 O(m)O(\sqrt m)O(m

这个问题可以通过枚举三元组并检查它们是否构成三元来解决。具体地,对于一个无向图 \( G \),我们需要找到所有包含三个点 \( u, v, w \) 的子图,并且这些点之间有三条边 \( \langle u,v \rangle, \langle v,w \rangle, \langle w,u \rangle \)。 以下是实现该算法的 C++ 代码: ```cpp #include <iostream> #include <vector> #include <unordered_set> using namespace std; int main() { int n, m; cin >> n >> m; // 使用邻接表存储图 vector<vector<int>> adj(n + 1); // 点从1开始编号 unordered_set<long long> edges; // 存储边的集合,用于快速查找 for (int i = 0; i < m; ++i) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); // 将每条边编码为一个唯一的long long值 if (u > v) swap(u, v); edges.insert(((long long)u << 32) | v); // 编码边为唯一值 } int count = 0; // 枚举每个点作为三元的一个点 for (int u = 1; u <= n; ++u) { // 对于点u的所有邻居v和w,检查是否存在边<v,w> for (size_t i = 0; i < adj[u].size(); ++i) { int v = adj[u][i]; for (size_t j = i + 1; j < adj[u].size(); ++j) { int w = adj[u][j]; // 检查边<v,w>是否存在 long long edge = ((long long)v << 32) | w; if (edges.find(edge) != edges.end()) { count++; } } } } // 每个三元被计算了6次(因为有3!种排列方式),所以需要除以6 cout << count / 6 << endl; return 0; } ``` ### 解释 1. **输入读取与图构建**: - 我们使用邻接表 `adj` 来存储图。 - 同时,为了快速检查某条边是否存在,我们使用 `unordered_set` 存储所有边。 - 每条边通过将两个端点按大小顺序排序后编码为一个唯一的 `long long` 值,这样可以方便地进行查找。 2. **三元计数**: - 对于图中的每个点 \( u \),我们枚举它的所有邻居对 \( (v, w) \)。 - 如果存在边 \( \langle v, w \rangle \),那么 \( u, v, w \) 构成一个三元。 - 由于每个三元会被计算多次(具体来说是 6 次,对应三元中点的不同排列方式),因此最后的结果需要除以 6。 3. **时间复杂度**: - 枚举每个点 \( u \) 的邻居对的时间复杂度为 \( O(m^2 / n) \),其中 \( m \) 是边数,\( n \) 是点数。 - 因此,总的时间复杂度为 \( O(m^{1.5}) \) 左右,适合处理中等规模的图。 4. **样例解释**: - 在样例中,输入的图是一个完整的三角形,因此只有一个三元。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值