HELLO WORLD--一起加油(🍺)!|

kingwzun

园龄:3年6个月粉丝:111关注:0

2022-09-07 11:29阅读: 216评论: 0推荐: 0

无向图三元环 查找/计数

理解

时间复杂度 O(MM)
作用
求出无向图的所有三元环

过程
首先要对所有的无向边进行定向,对于任何一条边,从度数大的点连向度数小的点,如果度数相同,从编号小的点连向编号大的点。

此时这张图是一个有向无环图。

  • 枚举每一个点u,然后将u的所有相邻的点都标记上“被u访问了”,
  • 然后再枚举u的相邻的点v,
  • 然后再枚举v的相邻的点w,
    如果w存在“被u访问了”的标记,那么(u,v,w)就是一个三元环了,且每个三元环只会被计算一次。

这样为什么是对的呢?
按照算法的流程,原来图中的一个三元环 ((i,j,k) 在重定向之后一定变成了 i 向 j,k 连边,j,k 之间再连一条边的情况,不妨设为jk
我们枚举 i 时会标记 j,k ,再遍历 j找第三个点的时候一定会找到 k 。
并且对于这个环,遍历顺序只可能是 ijk,也就是我们只能由 i 来找到这个环。每个点我们只会枚举一次,
所以图中的每一个三元环,我们都会遍历 且 仅遍历一次。

那么时间复杂度为什么 O(mm) 呢?

考虑每条边 (u,v) 对时间复杂度的贡献与 v 的出度同阶,总的时间复杂度应当是 i=1mdv,这里 d 是出度。

对于原图中度数不大于 m 的点,新图中的度数也不可能更大,所以上界 m

对于原图中度数大于 m 的点,由于我们只向度数大的点连边,而度数大于 m 的点最多有 m个,度数也不可能超过 m

综上,总的时间复杂度 O(mm)

模板代码1

时间复杂度 O(MM)
将边先存起来,然后再建图。
优点: 代码清晰,好看
缺点: 空间大些

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

时间复杂度 O(MM)
直接建图,然后通过判断限制,达到单向的目的。
优点: 空间优秀
缺点: 代码难看

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 中国大陆许可协议进行许可。

posted @   kingwzun  阅读(216)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起