【科技】三/四元环计数

【科技】三元环计数

介绍一个小科技,三元环计数,利用复杂度分析证明暴力求解是科学的。

具体问题就是,给定一张 n 个点,m 条边的简单无向图,求解无序三元组 (i,j,k)的数量,其中满足存在边 (i,j),(i,k),(j,k)

分析:

第一秒想到的是直接暴力枚举,但发现一个环上每个点都会把这个环算上一遍,纵使最后容斥除掉

但每个点为基础找三元环的复杂度也是很高的

考虑怎么才能让一个环只被算上一次,这样是最优化的了,再没有别的方法了

正解:

我们先把无向图转成有向图

给每个点定义一个双关键字(deg,id),其中deg表示度数,id表示标号

这样对于每一对点都能严格比较出大小

我们把每一条边重定向成从度数大的点连向度数小的点,我们就可以得到一张有向无环图。

具体怎么找环:

  1. 枚举一个点i,将所有i点连出的点标记为i
  2. 枚举一个点i连出的点j
  3. 枚举一个点j连出的点k,如果k的标记是i,那么就找到了一组三元环(i,j,k)

分析每一个三元环只会在i这个点被算到一次答案

可以证明这么做的复杂度的一个上界是O(m√m)

因为一个三元环在新图上必定只有一个点的出度为2,然后我们只在这个点上更新三元环数量

code :

#include<bits/stdc++.h>
using namespace std;
const int N = 250005;
int n, m, ans;
int a[N], du[N], vi[N], eu[N], ev[N];
vector<int> g[N];
inline bool cmp(int x, int y) {
  return du[x] != du[y]? du[x] > du[y] : x < y;
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);
  for (int i = 1; i <= m; ++i)
      scanf("%d%d", &eu[i], &ev[i]), ++du[eu[i]], ++du[ev[i]];
  for (int i = 1; i <= m; ++i)
    if (cmp(eu[i], ev[i])) g[eu[i]].push_back(ev[i]);
    else g[ev[i]].push_back(eu[i]);
  for (int i = 1; i <= n; ++i) {
    for (int j : g[i]) vi[j] = i;
    for (int j : g[i])
      for (int k : g[j])
        if (vi[k] == i) ++ans;
  }
  printf("%d\n", ans);
  return 0;
}

那四元环怎么办?

类似三元环还是要对边定向。

但此时注意枚举点 u 相邻的点 v 是原图中的边(而非重定向后的边),

而枚举 v相邻的点 w 则要是重定向后的点(可以交换图的顺序),

原因是我们相当于是枚举两个部分拼起来。

还是在 u 被枚举一次,因为 rk[u]<rk[w]

code:

inline bool cmp(const int& _this,const int& _that) 
	{return d[_this]<d[_that]||(d[_this]==d[_that]&&_this<_that);}
#define con const int&
inline void main() {
	n=g(),m=g(); for(R i=1,u,v;i<=m;++i) 
		u=g(),v=g(),e[u].push_back(v),e[v].push_back(u);
	for(R i=1;i<=n;++i) d[id[i]=i]=e[i].size();
	sort(id+1,id+n+1,cmp);
	for(R i=1;i<=n;++i) rk[id[i]]=i;
	for(R u=1;u<=n;++u) for(con v:e[u]) 
		if(rk[v]>rk[u]) f[u].push_back(v);
	for(R u=1;u<=n;++u) {
		for(con v:e[u]) for(con w:f[v]) if(rk[w]>rk[u]) ans+=c[w],++c[w]; //交换e与f的枚举顺序也是对的。
		for(con v:e[u]) for(con w:f[v]) if(rk[w]>rk[u]) c[w]=0; //清空桶。
	} printf("%lld\n",ans);
} 


posted @ 2019-11-04 15:34  wzx_believer  阅读(732)  评论(0编辑  收藏  举报