当前位置: 代码迷 >> 综合 >> luogu P1989 无向图三元环计数
  详细解决方案

luogu P1989 无向图三元环计数

热度:15   发布时间:2023-12-29 23:58:48.0

https://www.luogu.com.cn/problem/P1989

经典问题,
对于原图的每一条边u?>vu->vu?>v,如两点的度数不一样,那么就度数小的连向度数大的,否则编号小的连向编号大的
然后考虑新图的每一条边u?>vu->vu?>v遍历和vvv相连的每个点www,看www是否和uuu相连,不难发现这个的时间复杂度是∑out[vi]\sum out[v_i]out[vi?]

那么如何证明这个时间复杂度是O(mm)O(m\sqrt{m})O(mm ?)的呢?

考虑原图的一个点uuu,如果deg[u]≤mdeg[u]\le \sqrt{m}deg[u]m ?,显然出度≤m\le \sqrt{m}m ?
如果deg[u]>mdeg[u]>\sqrt{m}deg[u]>m ?,因为只能向度数比uuu大的点vvv连边,然而vvv的个数显然是不超过m\sqrt{m}m ?个的,所以显然正确

code:

#include<bits/stdc++.h>
#define N 2000050
using namespace std;
int n, m, in[N], vis[N];
vector<int> g[N];
struct E {
    int u, v;
} e[N << 1];
int main() {
    scanf("%d%d", &n, &m);for(int i = 1; i <= m; i ++) {
    scanf("%d%d", &e[i].u, &e[i].v);in[e[i].u] ++, in[e[i].v] ++;}for(int i = 1; i <= m ; i++) {
    int u = e[i].u, v = e[i].v;if(in[u] > in[v]) swap(u, v);if((in[u] == in[v]) && u > v) swap(u, v);g[u].push_back(v);}int ans = 0;for(int u = 1; u <= n; u ++) {
    for(int v : g[u]) vis[v] = u;for(int v : g[u])for(int w : g[v])if(vis[w] == u) ans ++;}printf("%d", ans);return 0;
}