P1989 无向图三元环计数 题解

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\) 的出度。

分类讨论:

  1. 如果无向图中 \(v\) 的度数 \(\le \sqrt m\),显然有向图中 \(v\) 的度数一定不超过无向图的度数,则有 \(oud_v\le \sqrt m\)
  2. 如果无向图中 \(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;
}

posted @ 2023-09-28 18:01  MoyouSayuki  阅读(14)  评论(0编辑  收藏  举报
:name :name