抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

顾名思义,环就是环

一般研究较多的是三元环和四元环计数。题目给定一张无向图,让你直接或间接地求图中有多少个不同的三元/四元环。形式化的,给定一张无向图,统计出满足要求的无序对 的个数,无序对需满足图中存在仅由点 组成的环。而且它还喜欢和容斥一起考(属实是出生到家了)。

三元环计数

对于三元环计数,我们有很好的算法可以解决,还能够顺带给出三元环的组成点分别是哪些。基本思路如下:

  1. 将所有边定向:统计每个点的度数,并让度数小的点指向度数大的点(原边基础上定向,不创建新边),若度数相同则编号小的点指向编号大的点。此时可以得到一张有向无环图
  2. 枚举每个点 的所有出点 ,并将 标记,再对 枚举其出点 ,检查 是否已被标记过,最终把 所有出点的标记清空。

其实听起来很暴力(尤其是第二步),但是它却能做到 的复杂度。太强辣

代码来自于:P1989 无向图三元环计数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <bits/stdc++.h>

#define N 100010
using namespace std;

struct Edge {
int to, ne;
} edges[N << 1];

int h[N], idx = 0;
int deg[N << 1];
bool st[N << 1];
int u[N << 1], v[N << 1];

void add(int a, int b) {
idx++;
edges[idx].to = b;
edges[idx].ne = h[a];
h[a] = idx;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

memset(h, -1, sizeof h);
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> u[i] >> v[i];
deg[u[i]]++;
deg[v[i]]++;
}
for (int i = 1; i <= m; i++) {
if ((deg[u[i]] == deg[v[i]] && u[i] > v[i]) || deg[u[i]] > deg[v[i]]) swap(u[i], v[i]);
add(u[i], v[i]);
}
int cnt = 0;
for (int u = 1; u <= n; u++) {
for (int i = h[u]; ~i; i = edges[i].ne) {
int j = edges[i].to;
st[j] = true;
}
for (int i = h[u]; ~i; i = edges[i].ne) {
int v = edges[i].to;
for (int j = h[v]; ~j; j = edges[j].ne) {
int w = edges[j].to;
if (st[w]) cnt++;
}
}
for (int i = h[u]; ~i; i = edges[i].ne) {
int j = edges[i].to;
st[j] = false;
}
}
cout << cnt << endl;
return 0;
}

如果使用上面这种方法,千万不要忘记数组开二倍。

四元环计数

基本步骤如下:

  1. 为无向边定向,思路同三元环计数。
  2. 设定一个辅助计数数组 cnt,在有向图上枚举点 的出点 ,再在原本的无向图上枚举 的出点 ,当 的度数严格大于 的度数时,答案累加 cnt[w],并把 cnt[w] 自增一,当前 枚举结束时把 cnt 清零。

例题

P9850 [ICPC2021 Nanjing R] Ancient Magic Circle in Teyvat

题目地址:P9850

题目难度:NOI/NOI+/CTSC

题目来源:ICPC  南京  2021

给定一个 个点的完全图,有 条边是红色的,其余边是蓝色的,求出边均为蓝色的大小为 的完全子图个数与边均为红色的大小为 的完全子图个数的差。

对所有数据满足,

将蓝色子图容斥掉,接着分类讨论选择的边数即可。

题解同步于本站

评论