P1989 无向图三元环计数 题解
考虑对无向图的边定向:对于每一条无向边,度数小的点向度数大的点连边,如果读书相等则按编号大小确定。
这样枚举一个 \(u\),再枚举它的出点 \(v\),接着枚举 \(v\) 的出点 \(w\),如果存在一个 \(w\),\(u\) 向它连边,那么 \((u, v, w)\),就对应了原图中的一个三元环。
这样的时间复杂度是 \(O(m\sqrt m)\) 的,证明如下:
可以发现,总共的计算次数就是 \(\sum_{(u, v)\in E} oud_v\),其中 \(E\) 是有向图的边集,\(out_v\) 是 \(v\) 的出度。
分类讨论:
- 如果无向图中 \(v\) 的度数 \(\le \sqrt m\),显然有向图中 \(v\) 的度数一定不超过无向图的度数,则有 \(oud_v\le \sqrt m\)
- 如果无向图中 \(v\) 的度数 \(> \sqrt m\),那么有向图中,由于 \(v\) 只会向度数不小于自己的连边,所以 \(v\) 的出点 \(w\) 一定有 \(oud_w > \sqrt m\),已知总度数为 \(2m\),则度数 \(> \sqrt m\) 的点的数量只有大约 \(\dfrac{2m}{\sqrt m} = 2\sqrt m\) 个,因此 \(w\) 的个数一定在 \(O(\sqrt m)\) 的量级,所以 \(oud_v = O(\sqrt m)\)。
综上所述,\(oud_v = O(\sqrt m)\)。
所以 \(\sum_{(u, v)\in E} oud_v = O(m\sqrt m)\)。
实现不难,代码如下:
// Problem: P1989 无向图三元环计数
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-09-28 17:31:48
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int N = 2e5 + 10;
vector<int> g[N];
int n, m, ind[N];
pair<int, int> e[N];
bool st[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1, a, b; i <= m; i ++) {
cin >> a >> b;
ind[a] ++, ind[b] ++;
e[i] = {a, b};
}
for(int i = 1; i <= m; i ++) {
if(ind[e[i].first] < ind[e[i].second] || (ind[e[i].first] == ind[e[i].second] && e[i].first < e[i].second)) g[e[i].first].push_back(e[i].second);
else g[e[i].second].push_back(e[i].first);
}
int ans = 0;
for(int i = 1; i <= n; i ++) {
for(auto v : g[i]) st[v] = 1;
for(auto v : g[i]) {
for(auto w : g[v])
if(st[w]) ans ++;
}
for(auto v : g[i]) st[v] = 0;
}
cout << ans << '\n';
return 0;
}
标签:度数,int,题解,sqrt,oud,无向,P1989
From: https://www.cnblogs.com/MoyouSayuki/p/17736295.html