Appearance
无向图环计数,扩展性较差。
主要有以下三类:
普通环计数
以下默认讨论无自环、无重边的简单无向图;简单环的长度至少为
在一般无向图中精确计数所有简单环是 #P-complete 的计数问题,而不是 P-complete。判定图中是否存在环本身可以在线性时间完成;困难的是精确计数。当前没有已知的多项式时间精确算法,通常只能在
和哈密顿路径类似,考虑状压 dp。
为避免同一个环从不同顶点开始而被重复统计,钦定环上编号最小的节点
令
当
时间复杂度:
因此最终答案直接除以
若题目讨论允许重边的多重图,并把两条不同的平行边视为长度为
三元环计数
给边定向,规定从度数小的点指向度数大的点,度数相同的点,由编号小的指向编号大的。
所有边都按“度数、编号”这一全序定向。先标记
可以证明,时间复杂度:
点击展开代码
cpp
for (int i = 1; i <= m; i++) {
if (deg[u[i]] < deg[v[i]])
add(u[i], v[i]);
else if (deg[v[i]] < deg[u[i]])
add(v[i], u[i]);
else if (u[i] < v[i])
add(u[i], v[i]);
else
add(v[i], u[i]);
}
long long ans = 0;
for (int i = 1; i <= n; i++) {
for (auto v : p[i])
vis[v] = 1;
for (auto u : p[i])
for (auto v : p[u])
if (vis[v])
ans++;
for (auto v : p[i])
vis[v] = 0;
}四元环计数
四元环即:
对边排序,度数小的排在前面,度数大的排在后面。
枚举度数大的点作为
因为
四元环数量可能超过 32 位整数范围,答案使用 long long 保存;若题目规模仍可能超过 64 位,则需使用大整数或按题意取模。
点击展开代码
cpp
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
a[i] = i;
auto cmp = [&](int x, int y) { return deg[x] < deg[y]; };
sort(a.begin() + 1, a.end(), cmp);
vector<int> rk(n + 1);
for (int i = 1; i <= n; i++)
rk[a[i]] = i;
for (int i = 1; i <= n; i++) {
for (auto u : p[i]) {
if (rk[u] < rk[i]) {
edge[i].push_back(u);
}
}
}
long long ans = 0;
vector<int> cnt(n + 1);
for (int i = 1; i <= n; i++) {
for (auto u : edge[a[i]]) {
for (auto v : p[u]) {
if (rk[v] >= rk[a[i]])
continue;
ans += cnt[v];
cnt[v]++;
}
}
for (auto u : edge[a[i]]) {
for (auto v : p[u]) {
cnt[v] = 0;
}
}
}五元环计数
无向图上,起止点相同的长度为五的路径只有两种情况:
- 五元环
- 三元环上插入一次沿某条边走出再返回的二步回走
长度为五的路径数,容易通过 dp 实现。
矩阵迹
时间复杂度:
dp 中的闭游走数量和最终答案都可能超过 32 位整数范围,统一使用 long long;若结果可能超过 64 位,则仍需使用大整数或取模。
点击展开代码
cpp
long long dp[6][N][N];
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
dp[1][u][v] = dp[1][v][u] = 1;
deg[u]++, deg[v]++;
}
for (int i = 2; i <= 5; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
for (int l = 1; l <= n; l++) {
dp[i][k][l] += dp[i - 1][k][j] * dp[1][j][l];
}
}
}
}
long long ans = 0;
for (int i = 1; i <= n; i++)
ans += dp[5][i][i];
ans /= 10;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int k = j + 1; k <= n; k++) {
if (dp[1][i][j] && dp[1][j][k] && dp[1][k][i]) {
ans -= 1LL * deg[i] + deg[j] + deg[k] - 3;
}
}
}
}固定长度 的环计数
本文暂未给出
当
有向图三元环计数
即:
对于 bitset 维护可达
枚举边 bitset 求交,时间复杂度:
