三元环计数四元环计数
三元环计数
问题
给出一张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)
三元环计数四元环计数相关推荐
- 【学习笔记】无向图、有向图的三元环、四元环计数问题(根号分支+bitset)
三元环计数和四元环计数问题 无向图三元环计数问题 根号分治 bitset 无向图四元环计数问题 有向图三四元环计数问题 无向图三元环计数问题 根号分治 记 di:id_i:idi:i 在原图中的度数 ...
- 【编译原理】:如何将控制语句翻译成四元式
如图: 解决这个问题的方法是: 翻译成三元式(逻辑就能翻译) 三元式转换为四元式 四元式结果 Op arg1 arg2 存储变量 知道这个思路之后,我们就能够很快的做出这道题了
- 【编译原理】 如何将控制语句翻译成四元式
如图: 解决这个问题的方法是: 翻译成三元式(逻辑就能翻译) 三元式转换为四元式 四元式结果 Op arg1 arg2 存储变量 知道这个思路之后,我们就能够很快的做出这道题了
- 期末考试:编译原理——如何将控制语句翻译成四元式.
一 例题 二 总结 1. 将原式翻译成三元式(逻辑就能翻译) 2. 三元式转换为四元式(Op arg1 arg2 存储变量) 3. 常见的变化规则 1. 判断语句 2. 赋值语句
- 编译原理-语法制导翻译、后缀表达式、三元、四元
此时的每条规则后面会对应一条语义动作,即制导翻译. 一.中间语言 中间语言就是和源程序等价的一种编码方式,复杂性也是介于源程序和机器语言中间. 为什么要中间语言? 我们经常可能会遇到过代码优化的选项, ...
- 2022第十四届环泰山T60线上大徒步活动线下启动仪式圆满结束
2022年12月3日,第十四届环泰山T60线上大徒步活动线下启动仪式在泰山脚下举行.今年因为疫情的原因,为了保障大家的安全,第十四届环泰山T60大徒步活动选择线上举行.本次线上活动由泰安市一五四五户外 ...
- 四甲基环四硅氧烷D4H
D4H[四甲基环四硅氧烷] 化学名称是:1,3,5,7-四甲基环四硅氧烷 中文名 D4H环四硅氧烷 CAS 2370-88-9 EINECS 219-137-4 别 名 含氢D4 别 名:2,4,6, ...
- 二元一次方程组、三元一次方程组、四元一次方程组解析解(代码)
文章目录 一.二元一次方程组解析解 二.三元一次方程组解析解 三.四元一次方程组解析解 一.二元一次方程组解析解 clc clearsyms a11 a12 a21 a22 b1 b2 real x ...
- y7000p 2020 vbios_2020年冬季千元环300公里上笼验资明细-长沙市南湖赛鸽俱乐部
2020年冬季千元环300公里上笼验资明细 序号 鸽棚号 鸽 主 名 称 足 环 号 码 1 000001 吴军 2020-18-0041037 2 000001 吴军 2020-18-0041038 ...
最新文章
- JavaScript中的普通函数与构造函数比较
- 当你在应用机器学习时你应该想什么
- javascript 相关小的知识点集合
- java JFileChooser选择文件和保存文件
- HTML DOM教程 19-HTML DOM Button 对象
- java mysql 二级缓存_深入理解MyBatis中的一级缓存与二级缓存
- 性能优化—— 代码优化
- (转)策略回测的框架、实现、测试
- Thymeleaf 模板布局三种区别
- 我用 Python 抓取了 7000 多本电子书
- NetAssist连接报错!
- 主流NoSQL数据库评测之HandlerSocket
- 网站服务器诊断分析,网站SEO优化诊断分析报告范文模板(一)
- AS 使用Statistic插件统计代码行数
- 弱密码验证不能连续字符(如123、abc)连续3位或3位以上、不能相同字符(如111、aaa)连续3位或3位以上
- ᑋᵉᑊᑊᵒ ᵕ̈ᰔᩚ
- 编译原理(四) 消除回溯提取左因子法
- opencore黑苹果教程
- 备份数据库、恢复数据库
- 九度OJ-1185:特殊排序
热门文章
- quicktype游戏java程序_使用QuickType工具从json自动生成类型声明代码
- mysql直接生成excel_MYSQL 将excel里面的数据直接生成sql语句
- leetcode704二分法:(左闭右闭+左闭右开)
- 7-28 搜索树判断 (25 分)(思路加详解) just easy!
- [蓝桥杯2019初赛]修改数组-并查集
- 数据结构基础概念、逻辑结构、物理结构
- Deeplab训练时候unexpected label
- 统计学习笔记(1) 监督学习概论(1)
- 2021牛客第一场H.Hash Function—FFT求差值的卷
- 2019 ICPC World Finals Problem J. Miniature Golf