给一张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; }