【科技】三元環計數


介紹一個小科技,三元環計數,利用復雜度分析證明暴力求解是科學的。

 具體問題就是,給定一張 $n$ 個點,$m$ 條邊的簡單無向圖,求解無序三元組 $(i,j,k)$ 的數量,其中滿足存在邊 $(i,j), (j,k),(i,k)$。

 我們先把無向圖轉成有向圖,並給每個點定義一個雙關鍵字$(deg_{i}, id_{i})$,其中$deg$表示度數,$id$表示標號,這樣對於每一對點都能嚴格比較出大小。

我們把每一條邊重定向成從度數大的點連向度數小的點,我們就可以得到一張有向無環圖。

具體怎么找環:

  1. 枚舉一個點$i$,將所有$i$點連出的點標記為$i$。
  2. 枚舉一個$i$連出的點$j$。
  3. 枚舉一個$j$連出的點$k$,如果$k$的標記是$i$,那么就找到了一組三元環$(i,j,k)$。

 分析每一個三元環只會在$i$這個點被算到一次答案。

下面簡要證明這么做的復雜度的一個上界是$O(m \sqrt{m})$。

 考慮重定向后的每條邊$(u,v)$,它對復雜度造成的貢獻就是$out_{v}$,其中$out$表示每個點的出度。

復雜度就是$\sum\limits_{i=1}^{m} out_{v}$。

  1. 對於所有的$v$,$out_{v} \leq \sqrt{m}$,每一次枚舉$v$連出的點不會超過$O(\sqrt{m})$,$m$次的總復雜度不會超過$O(m\sqrt{m})$。
  2. 對於所有的$v$,$out_{v} \geq \sqrt{m}$,必然有$deg_{u} \geq deg_{v} \geq \sqrt{m}$,由於$2m = \sum\limits_{i=1}^{n}deg_{i}$,所有這樣的$u$不會超過$\sqrt{m}$個,也就是每一個$out_{v}$的貢獻做多是$\sqrt{m} out_{v}$,由於$\sum\limits_{v}out_{v} \leq m$,所以總復雜度不會超過$O(m \sqrt{m})$。

這樣算三元環的復雜度就科學啦。

 

#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 250005;

int n, m, ans;
int a[N], du[N], vi[N], eu[N], ev[N];
vector<int> g[N];

inline bool cmp(int x, int y) {
  return du[x] != du[y]? du[x] > du[y] : x < y;
}

int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i)
    scanf("%d", &a[i]);
  for (int i = 1; i <= m; ++i)
    scanf("%d%d", &eu[i], &ev[i]), ++du[eu[i]], ++du[ev[i]];
  for (int i = 1; i <= m; ++i)
    if (cmp(eu[i], ev[i])) g[eu[i]].push_back(ev[i]);
    else g[ev[i]].push_back(eu[i]);
  for (int i = 1; i <= n; ++i) {
    for (int j : g[i]) vi[j] = i;
    for (int j : g[i])
      for (int k : g[j])
        if (vi[k] == i) ++ans;
  }
  printf("%d\n", ans);
  return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM