給一張n個點m條邊的無向圖,問有多少個\(A-structure\)
其中\(A-structure\)知足\(V=(A,B,C,D)\) && \(E=(AB,BC,CD,DA,AC)\)php
顯然\(A-structure\)是由兩個有公共邊的三元環構成的
\(1 <=n <= 1e5\)
\(1 <= m <= min(2e5,n*(n-1)/2)\)c++
三元環計數
作法一、
①統計每一個點的度數
②入度\(<=sqrt(m)\)的分爲第一類,入度\(>sqrt(m)\)的分爲第二類
③對於第一類,暴力每一個點,而後暴力這個點的任意兩條邊,再判斷這兩條邊的另外一個端點是否鏈接
由於\(m\)條邊最多每條邊遍歷一次,而後暴力的點的入度\(<=sqrt(m)\),因此複雜度約爲\(O(msqrt(m))\)
④對於第二類,直接暴力任意三個點,判斷這三個點是否構成環,由於這一類點的個數不會超過\(sqrt(m)\)個,因此複雜度約爲\(O(sqrt(m)^3)=O(msqrt(m))\)
⑤判斷兩個點是否鏈接能夠用set,map和Hash都行,根據具體狀況而行
這種作法建的是雙向邊,常數很大spa
更優的作法二、建有向邊 複雜度爲\(O(msqrt(m))\)
對全部邊按照兩端點的度數定向,度數小的往度數大的走,度數相同則按編號小到大走,這樣定向後
能夠保證是個有向無環圖。
爲何呢,要想定向存在環,則這個環上的點度數必須相同,因爲保證了編號從小到大走
因此是不可能存在環的。
這樣定向同時還保證了每一個點的出度不超過\(sqrt(m)\),很容易證實,若是存在一個點出度超過了\(sqrt(m)\),則說明存在其餘\(sqrt(m)\)個點的度數\(>sqrt(m)\),算起來超過邊數\(m\)了。code
對於這道題,咱們在求三元環的時候,統計一下每條邊有多少對點能構成三元環,\(C(cnt,2)\)累計一下便可get
作法一、it
#include<bits/stdc++.h> #define LL long long using namespace std; void read(int &x){ x = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar(); } const int N = 1e5 + 10; set<LL> g; int deg[N]; vector<int> G[N]; int vis[N],vi[N]; int main(){ int n, m, u, v, Sz; while(scanf("%d%d",&n,&m) != EOF){ Sz = sqrt(m + 0.5); g.clear(); for(int i = 1;i <= n;i++){ vis[i] = vi[i] = deg[i] = 0; G[i].clear(); } for(int i = 0;i < m;i++){ scanf("%d%d",&u,&v); g.insert(u + 1LL * v * n); g.insert(v + 1LL * u * n); deg[u]++,deg[v]++; G[u].push_back(v); G[v].push_back(u); } LL ans = 0; for(int u = 1;u <= n;u++){ vis[u] = 1; for(auto v:G[u]) vi[v] = u; for(auto v:G[u]){ int cnt = 0; if(vis[v]) continue; if(deg[v] <= Sz){ for(auto vv:G[v]){ if(vi[vv] == u) cnt++; } }else{ for(auto vv:G[u]){ if(g.find(1LL * v * n + vv) != g.end()) cnt++; } } ans += 1LL * cnt * (cnt - 1) / 2; } } printf("%lld\n",ans); } return 0; }
作法2、class
#include<bits/stdc++.h> #define LL long long #define P pair<int,int> using namespace std; void read(int &x){ x = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar(); } const int N = 1e5 + 10; set<LL> g; int deg[N]; vector<pair<int,int> > G[N]; int vi[N]; int X[N * 2],Y[N * 2],cnt[N],pos[N]; int main(){ int n, m, u, v, Sz; while(scanf("%d%d",&n,&m) != EOF){ Sz = sqrt(m); for(int i = 1;i <= n;i++){ vi[i] = deg[i] = pos[i] = 0; G[i].clear(); } g.clear(); int tot = 0; for(int i = 0;i < m;i++){ scanf("%d%d",&X[i],&Y[i]); u = X[i],v = Y[i]; deg[u]++,deg[v]++; } for(int i = 0;i < m;i++){ cnt[i] = 0; if(deg[X[i]] < deg[Y[i]]) G[X[i]].push_back(make_pair(Y[i],i)); else if(deg[Y[i]] < deg[X[i]]) G[Y[i]].push_back(P(X[i],i)); else{ if(X[i] < Y[i]) G[X[i]].push_back(P(Y[i],i)); else G[Y[i]].push_back(P(X[i],i)); } } LL ans = 0; for(int i = 0;i < m;i++){ u = X[i],v = Y[i]; for(auto vp:G[u]) pos[vp.first] = vp.second,vi[vp.first] = i + 1; for(auto vp:G[v]){ int vv = vp.first; if(vi[vv] == i + 1){ cnt[i]++; cnt[pos[vv]]++; cnt[vp.second]++; } } } for(int i = 0;i < m;i++) ans += 1LL * cnt[i] * (cnt[i] - 1) / 2; printf("%lld\n",ans); } return 0; }