无向图三元环 查找/计数
理解
时间复杂度
作用
求出无向图的所有三元环
过程
首先要对所有的无向边进行定向,对于任何一条边,从度数大的点连向度数小的点,如果度数相同,从编号小的点连向编号大的点。
此时这张图是一个有向无环图。
- 枚举每一个点u,然后将u的所有相邻的点都标记上“被u访问了”,
- 然后再枚举u的相邻的点v,
- 然后再枚举v的相邻的点w,
如果w存在“被u访问了”的标记,那么(u,v,w)就是一个三元环了,且每个三元环只会被计算一次。
这样为什么是对的呢?
按照算法的流程,原来图中的一个三元环 在重定向之后一定变成了 i 向 j,k 连边,j,k 之间再连一条边的情况,不妨设为 。
我们枚举 i 时会标记 j,k ,再遍历 j找第三个点的时候一定会找到 k 。
并且对于这个环,遍历顺序只可能是 ,也就是我们只能由 i 来找到这个环。每个点我们只会枚举一次,
所以图中的每一个三元环,我们都会遍历 且 仅遍历一次。
那么时间复杂度为什么 呢?
考虑每条边 对时间复杂度的贡献与 的出度同阶,总的时间复杂度应当是 ,这里 是出度。
对于原图中度数不大于 的点,新图中的度数也不可能更大,所以上界 。
对于原图中度数大于 的点,由于我们只向度数大的点连边,而度数大于 的点最多有 个,度数也不可能超过 。
综上,总的时间复杂度 。
模板代码1
时间复杂度
将边先存起来,然后再建图。
优点: 代码清晰,好看
缺点: 空间大些
int n,m; vector<int> g[N]; vector<pii> vec; int d[N]; int vis[N]; int get_sum(){ int ans=0; for(int i=1;i<=n;i++){ for(int j: g[i]) vis[j]=1; for(int j:g[i]) for(int k:g[j]) if(vis[k]) ans++; for(int j: g[i]) vis[j]=0; } return ans; } void solve(){ cin>>n>>m; for(int i=0;i<m;i++){ int u,v;cin>>u>>v; d[u]++,d[v]++; vec.push_back({u,v}); } for(pii t: vec){ int u=t.first,v=t.second; if(d[u]>d[v] ||(d[u]==d[v] && u>v)) swap(u,v); g[u].push_back(v); } cout<<get_sum()<<endl; }
模板代码2
时间复杂度
直接建图,然后通过判断限制,达到单向的目的。
优点: 空间优秀
缺点: 代码难看
int n, m; vector<int> g[N]; int vis[N]; int get_sum() { int ans=0; for (int i = 1; i <= n; i++) { for (int j : g[i]) if(g[i].size()>g[j].size() || (g[i].size()==g[j].size() && i>j)) vis[j] = 1; for (int j : g[i]) if(g[i].size()>g[j].size() || (g[i].size()==g[j].size() && i>j)) for (int k : g[j]) if(g[j].size()>g[k].size() || (g[j].size()==g[k].size() && j>k)) if (vis[k]) ans++; for (int j : g[i]) if(g[i].size()>g[j].size() || (g[i].size()==g[j].size() && i>j)) vis[j] = 0; } return ans; } void solve(){ cin>>n>>m; for(int i=0;i<m;i++){ int u,v;cin>>u>>v; g[u].push_back(v); g[v].push_back(u); } cout<<get_sum()<<endl; }
模板题
P1989 无向图三元环计数
代码
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> const int N=1e5+10; const int mod=1e9+7; int n,m; vector<int> g[N]; vector<pii> vec; int d[N]; int vis[N]; int get_sum(){ int ans=0; for(int i=1;i<=n;i++){ for(int j: g[i]) vis[j]=1; for(int j:g[i]) for(int k:g[j]) if(vis[k]) ans++; for(int j: g[i]) vis[j]=0; } return ans; } void solve(){ cin>>n>>m; for(int i=0;i<m;i++){ int u,v;cin>>u>>v; d[u]++,d[v]++; vec.push_back({u,v}); } for(pii t: vec){ int u=t.first,v=t.second; if(d[u]>d[v] ||(d[u]==d[v] && u>v)) swap(u,v); g[u].push_back(v); } cout<<get_sum()<<endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t=1; // cin>>t; while(t--) solve(); return 0; }
C - Friend-Graph HDU - 6152
注意及时剪枝结束,不然会超时。
代码
#include <bits/stdc++.h> using namespace std; // #define int long long // #define pii pair<int, int> //***********************必不可少,不然内存超限 // #define int short int const int N = 3010; const int mod = 1e9 + 7; int n, m; vector<int> g[N]; int vis[N]; int get_sum() { for (int i = 1; i <= n; i++) { for (int j : g[i]) if(g[i].size()>g[j].size() || (g[i].size()==g[j].size() && i>j)) vis[j] = 1; for (int j : g[i]) if(g[i].size()>g[j].size() || (g[i].size()==g[j].size() && i>j)) for (int k : g[j]) if(g[j].size()>g[k].size() || (g[j].size()==g[k].size() && j>k)) if (vis[k]) return 1; for (int j : g[i]) if(g[i].size()>g[j].size() || (g[i].size()==g[j].size() && i>j)) vis[j] = 0; } return 0; } void init() { m = 0; for (int i = 1; i <= n; ++i) g[i].clear(); } void solve() { cin >> n; init(); for (int i = 1; i <= n - 1; i++){ for (int j = i + 1; j <= n; j++){ int t;cin >> t; if (t){ m++; g[i].push_back(j); g[j].push_back(i); } } } int ans1 = 0, ans2 = 0; ans1 = get_sum(); m = n * (n - 1) / 2 - m; //反向建边 for (int i = 1; i <= n; ++i) { memset(vis, 0, sizeof vis); for (int j : g[i]) { vis[j] = 1; } g[i].clear(); for (int j = 1; j <= n; j++) { if (vis[j] == 0) g[i].push_back(j); } } ans2 = get_sum(); if (ans1 == 0 && ans2 == 0) cout << "Great Team!" << endl; else cout << "Bad Team!" << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t = 1; cin >> t; while (t--) solve(); return 0; }
原文1:https://blog.51cto.com/u_15072778/3772333
原文2:https://www.luogu.com.cn/blog/i207M/san-yuan-huan-ji-shuo-xue-xi-bi-ji
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16664770.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步