无向图三元环计数
本篇博客参考这篇博客,然后根据自己的理解补了一点小细节,如果想看原文可以去这里
题意#
给定一张简单无向图,请求出图中的三元环个数,其中三元环的定义是一个三元组,其中,,均有边直接相连
做法#
首先对所有边进行定向,对于任何一条边,从度数小的边连向度数大的边,如果度数相同,则从编号小的边连向编号大的边.
注意这里的度数是指无向图中的度数,也就是一条边同时会给这条边的两个端点增加度数
然后我们通过这种方法就能得到一张有向无环图,我们枚举每个点,然后将在有向图中能直接到达的边标记为被访问过,然后再枚举所有在有向图能直接到达的点,如果相邻的点中有一个点被访问过,那么这就是一个三元环
证明#
有向无环#
首先证明我们得到的图是一张有向无环图
如果在我们定向后的图中存在环,那么在原来的无向图中这个也一定是个环.我们假设一个环为,那么按照我们的连边规则,那么会有
发现这个不等式成立时只有这一种情况,但是当度数相等时我们按照编号大小连边,又因为这个不等式显然不成立,所以这个环无论如何都不会存在
综上,这张图有向,而且没有环,所以是一张有向无环图(嗯
时间复杂度#
我们会枚举所有点,并且把所有枚举到的点都打上能到达的标记,所以复杂度为
然后我们考虑枚举一个点能到的所有点再枚举它能到的所有点,这个本质上是枚举
首先考虑当的情况,因为有一条边,所以,而这种点的数量显然不超过数量级,所以这部分的复杂度为
然后考虑当时的情况,,因为有一条边,所以,而这种点的数量显然不超过数量级,所以这部分的复杂度为
综上,时间复杂度为
代码#
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; vector<int> g[N]; int deg[N], vis[N], n, m, ans; struct E { int u, v; } e[N * 3]; int main() { scanf("%d%d", &n, &m); for(int i = 1 ; i <= m ; ++ i) { scanf("%d%d", &e[i].u, &e[i].v); ++ deg[e[i].u], ++ deg[e[i].v]; } for(int i = 1 ; i <= m ; ++ i) { int u = e[i].u, v = e[i].v; if(deg[u] < deg[v] || (deg[u] == deg[v] && u > v)) swap(u, v); g[u].push_back(v); } for(int x = 1 ; x <= n ; ++ x) { for(auto y: g[x]) vis[y] = x; for(auto y: g[x]) for(auto z: g[y]) if(vis[z] == x) ++ ans; } printf("%d\n", ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】