无向图三元环计数

Description

P1989 无向图三元环计数

给定简单无向图 \(G=(V,E)\),求其三元环个数,其中 \(\lvert V\rvert\leq10^5,\lvert E\rvert\leq 2\times 10^5\)

Solution

考虑给每一个边定一个方向。具体地,对于原图的一条边 \(E=(u,v)\),有

  • \(\deg_u>\deg_v\)\(\text{deg}_u=\text{deg}_v\land u<v\),则 \(u\to v\)
  • 否则 \(v\to u\)

给边定完方向后,原图变成了一个有向无环图 。

注意到原图中的三元环一定与对应有向图中所有形如 \(E'=(u\to v,u\to w,v\to w)\) 的子图一一对应。

只需要枚举 \(u\) 的出边,再枚举 \(v\) 的出边,然后检查 \(w\) 是否为 \(u\) 指向的点即可。时间复杂度为 \(\mathcal O(m\sqrt m)\)

  • 为什么时间复杂度为 \(O(m\sqrt m)\)​?

首先在在枚举 \(u\) 的出边时打上 \(u\) 的时间戳,这样在枚举 \(v\) 的出边时可以 \(O(1)\) 判断。

那么考虑每一条边 \(u\to v\) 的贡献为 \(out_v\),所以总复杂度为 \(\sum\limits_{i=1}^{m} out_{v_i}\),其中 \(v_i\) 是第 \(i\) 条边指向的点, \(out_v\) 是点 \(v\)​ 的出度。

对于每一个点 \(v\) 分情况讨论。

  1. 当在原图上 \(\deg_v\leq\sqrt m\) 时,由于新图每个节点的出度不可能大于原图的度数,所以 \(out_v=O(\sqrt m)\)
  2. 当在原图上 \(\deg_v>\sqrt m\) 时,注意到它只能向原图中度数不小于它的点连边,又因为原图中所有的点的度数和为 \(O(m)\),所以原图中 \(\deg>\sqrt m\) 的点只有 \(O(\sqrt m)\) 个。因此 \(v\) 的出边只有 \(O(\sqrt m)\) 条,即 \(out_v=O(\sqrt m)\)

综上所有点的度数都为 \(O(\sqrt m)\),总复杂度就为 \(O(m\sqrt m)\)

Code

const int N=1e5+5;
int n,m,deg[N],vis[N],ans;
struct E{int u,v;}e[N*3];
vector<int>G[N];

signed main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        e[i]=(E){read(),read()};
        deg[e[i].u]++;deg[e[i].v]++;
    }
    for(int i=1;i<=m;i++){
        int u=e[i].u,v=e[i].v;
        if(deg[u]<deg[v] or (deg[u]==deg[v] and u>v))
            swap(u,v);
        G[u].eb(v);
    }
    for(int u=1;u<=n;u++){
        for(auto v:G[u])
            vis[v]=u;
        for(auto v:G[u])
            for(auto w:G[v])
                if(vis[w]==u)
                    ans++;
    }
    write(ans);
    return 0;
}
posted @   QcpyWcpyQ  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示