三元环计数

问题

给出一张n个点m条边的无向图,问图中有多少个三元组{ u , v , w } ,满足图中存在 { (u,v) , (v,w) , (w,u) } 三条边。

求解

Step1 定向

将所有点按 度数 从小到大排序,如果度数相同按 点编号 从小到大排序,u的排名记作 rnkurnk_urnku​。

将这张图转化为有向图:对于一条无向边 x − y ,若 rnkx>rnkyrnk_x>rnk_yrnkx​>rnky​,那么就将这条无向边变成 x → y 。反之则反之。

这样转化后,这张图一定是 有向无环图

证明:

使用反证法,假设有一个环:a→b→c→aa\to b \to c \to aa→b→c→a,
那么有(设 x 的度数为 dxd_xdx​):
da≥db≥dc≥dad_a \geq d_b \geq d_c \geq d_ada​≥db​≥dc​≥da​,要使该不等式成立,当且仅当满足 da=db=dc=dad_a = d_b = d_c = d_ada​=db​=dc​=da​。

设 x 的编号为 idxid_xidx​,那么有:ida>idb>idc>idaid_a>id_b>id_c>id_aida​>idb​>idc​>ida​,即 ida>ida>ida>idaid_a > id_a > id_a > id_aida​>ida​>ida​>ida​,该式子不成立,故假设不成立,证毕。

Step2 暴力枚举

枚举一个点 u 和它的所有出边到的点 v 并标记,再枚举 v 的出边到的点 w,如果 w 也有标记则表示找到了一个三元环

这样,每个三元环只会在 u 被统计一次(rnkurnk_urnku​在三元环中是最大的)

Code

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+5;
const int M=2e5+5;
struct Edge{int v,nxt;
}edge[M<<1];
int n,m,head[N],cnt,a[M],b[M];
int d[N],ans,mark[N];
void add_edge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
bool cmp(int a,int b){if(d[a]==d[b]) return a>b;return d[a]>d[b];
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d",&a[i],&b[i]);d[a[i]]++;d[b[i]]++;}for(int i=1;i<=m;i++){if(d[a[i]]>d[b[i]]||(d[a[i]]==d[b[i]]&&a[i]>b[i]))add_edge(a[i],b[i]);else add_edge(b[i],a[i]);}for(int u=1;u<=n;u++){for(int i=head[u];i;i=edge[i].nxt) mark[edge[i].v]=u;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;for(int j=head[v];j;j=edge[j].nxt){int w=edge[j].v;if(mark[w]==u) ans++;}}}printf("%d\n",ans);return 0;
}

时间复杂度

考虑每一条边被遍历的次数:对于一条边 x→yx\to yx→y,他被遍历的次数为 inxin_xinx​ 。(inxin_xinx​表示 x 的入度),那么总的时间复杂度就是每一条边的 inxin_xinx​ 之和。

又可以发现,inxin_xinx​ 的上限就是 m\sqrt mm​,因为要求每个连向 x 的点的度都大于 inxin_xinx​ ,也就是说,有 inxin_xinx​ 个点的度数大于inxin_xinx​,这样就至少需要 inx2in_x^2inx2​ 条边,所以 inx2≤m⇒inx≤min_x^2\leq m ⇒ in_x \leq \sqrt minx2​≤m⇒inx​≤m​

所以总时间复杂度 O(mm)O(m\sqrt m)O(mm​)

四元环计数

问题

给出一张n个点m条边的无向图,问图中有多少个四元组{ u , v , w ,x } ,满足图中存在 { (u,v) , (v,w) , (w,x),(x,u) } 四条边。

求解

Step1 定向

同三元组计数

Step2 暴力枚举

枚举一个点 u 和它的所有 出边 到的点 v ,然后枚举 v 的 无向边 到的点 w,其中要求 rnku>rnkwrnk_u>rnk_wrnku​>rnkw​

每访问到一个 w 给答案加上 w 的标记,并给 w 的标记加 1

这样,每个四元环只会在 u 被统计一次(rnkurnk_urnku​在四元环中是最大的)

Code

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+5;
const int M=2e5+5;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
struct Edge{int v,nxt;
}edge[M<<1],e[M<<1];
int n,m,head[N],cnt,hd[N],ct,a[M],b[M];
int d[N],mark[N],tmp[N];
long long ans;
void add_edge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void add_e(int u,int v){e[++ct].v=v;e[ct].nxt=hd[u];hd[u]=ct;
}
bool cmp(int a,int b){if(d[a]==d[b]) return a>b;return d[a]>d[b];
}
int main(){n=read();m=read();for(register int i=1;i<=m;i++){a[i]=read();b[i]=read();d[a[i]]++;d[b[i]]++;add_e(a[i],b[i]);add_e(b[i],a[i]);}for(register int i=1;i<=m;i++){if(d[a[i]]>d[b[i]]||(d[a[i]]==d[b[i]]&&a[i]>b[i]))add_edge(a[i],b[i]);elseadd_edge(b[i],a[i]);}ans=0;for(register int u=1;u<=n;u++){for(register int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;for(register int j=hd[v];j;j=e[j].nxt){int w=e[j].v;if(d[u]>d[w]||(d[u]==d[w]&&u>w)){ans+=1ll*tmp[w];tmp[w]++;}}}for(register int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;for(register int j=hd[v];j;j=e[j].nxt){int w=e[j].v;if(d[u]>d[w]||(d[u]==d[w]&&u>w)) tmp[w]=0;}}}printf("%lld\n",ans);return 0;
}

时间复杂度

O(mm)O(m\sqrt m)O(mm​)

证明(自己想的,不保证对):

对于边x−yx - yx−y,假设它定向后为 x→yx \to yx→y,
那么作为无向边它被遍历 inx+inyin_x+in_yinx​+iny​ 次,作为有向边被遍历 inxin_xinx​ 次,总过被遍历 2inx+iny2in_x+in_y2inx​+iny​ 次

总复杂度仍是 O(mm)O(m\sqrt m)O(mm​)

三元环计数四元环计数相关推荐

  1. 【学习笔记】无向图、有向图的三元环、四元环计数问题(根号分支+bitset)

    三元环计数和四元环计数问题 无向图三元环计数问题 根号分治 bitset 无向图四元环计数问题 有向图三四元环计数问题 无向图三元环计数问题 根号分治 记 di:id_i:idi​:i 在原图中的度数 ...

  2. 【编译原理】:如何将控制语句翻译成四元式

    如图: 解决这个问题的方法是: 翻译成三元式(逻辑就能翻译) 三元式转换为四元式 四元式结果 Op arg1 arg2 存储变量 知道这个思路之后,我们就能够很快的做出这道题了

  3. 【编译原理】 如何将控制语句翻译成四元式

    如图: 解决这个问题的方法是: 翻译成三元式(逻辑就能翻译) 三元式转换为四元式 四元式结果 Op arg1  arg2  存储变量 知道这个思路之后,我们就能够很快的做出这道题了

  4. 期末考试:编译原理——如何将控制语句翻译成四元式.

    一 例题 二 总结 1. 将原式翻译成三元式(逻辑就能翻译) 2. 三元式转换为四元式(Op arg1 arg2 存储变量) 3. 常见的变化规则 1. 判断语句 2. 赋值语句

  5. 编译原理-语法制导翻译、后缀表达式、三元、四元

    此时的每条规则后面会对应一条语义动作,即制导翻译. 一.中间语言 中间语言就是和源程序等价的一种编码方式,复杂性也是介于源程序和机器语言中间. 为什么要中间语言? 我们经常可能会遇到过代码优化的选项, ...

  6. 2022第十四届环泰山T60线上大徒步活动线下启动仪式圆满结束

    2022年12月3日,第十四届环泰山T60线上大徒步活动线下启动仪式在泰山脚下举行.今年因为疫情的原因,为了保障大家的安全,第十四届环泰山T60大徒步活动选择线上举行.本次线上活动由泰安市一五四五户外 ...

  7. 四甲基环四硅氧烷D4H

    D4H[四甲基环四硅氧烷] 化学名称是:1,3,5,7-四甲基环四硅氧烷 中文名 D4H环四硅氧烷 CAS 2370-88-9 EINECS 219-137-4 别 名 含氢D4 别 名:2,4,6, ...

  8. 二元一次方程组、三元一次方程组、四元一次方程组解析解(代码)

    文章目录 一.二元一次方程组解析解 二.三元一次方程组解析解 三.四元一次方程组解析解 一.二元一次方程组解析解 clc clearsyms a11 a12 a21 a22 b1 b2 real x ...

  9. y7000p 2020 vbios_2020年冬季千元环300公里上笼验资明细-长沙市南湖赛鸽俱乐部

    2020年冬季千元环300公里上笼验资明细 序号 鸽棚号 鸽 主 名 称 足 环 号 码 1 000001 吴军 2020-18-0041037 2 000001 吴军 2020-18-0041038 ...

最新文章

  1. JavaScript中的普通函数与构造函数比较
  2. 当你在应用机器学习时你应该想什么
  3. javascript 相关小的知识点集合
  4. java JFileChooser选择文件和保存文件
  5. HTML DOM教程 19-HTML DOM Button 对象
  6. java mysql 二级缓存_深入理解MyBatis中的一级缓存与二级缓存
  7. 性能优化—— 代码优化
  8. (转)策略回测的框架、实现、测试
  9. Thymeleaf 模板布局三种区别
  10. 我用 Python 抓取了 7000 多本电子书
  11. NetAssist连接报错!
  12. 主流NoSQL数据库评测之HandlerSocket
  13. 网站服务器诊断分析,网站SEO优化诊断分析报告范文模板(一)
  14. AS 使用Statistic插件统计代码行数
  15. 弱密码验证不能连续字符(如123、abc)连续3位或3位以上、不能相同字符(如111、aaa)连续3位或3位以上
  16. ᑋᵉᑊᑊᵒ ᵕ̈ᰔᩚ
  17. 编译原理(四) 消除回溯提取左因子法
  18. opencore黑苹果教程
  19. 备份数据库、恢复数据库
  20. 九度OJ-1185:特殊排序

热门文章

  1. quicktype游戏java程序_使用QuickType工具从json自动生成类型声明代码
  2. mysql直接生成excel_MYSQL 将excel里面的数据直接生成sql语句
  3. leetcode704二分法:(左闭右闭+左闭右开)
  4. 7-28 搜索树判断 (25 分)(思路加详解) just easy!
  5. [蓝桥杯2019初赛]修改数组-并查集
  6. 数据结构基础概念、逻辑结构、物理结构
  7. Deeplab训练时候unexpected label
  8. 统计学习笔记(1) 监督学习概论(1)
  9. 2021牛客第一场H.Hash Function—FFT求差值的卷
  10. 2019 ICPC World Finals Problem J. Miniature Golf