Counting Stars
题目链接:HDU - 6184题意:
现有一个图, 在图中找出特定的集合A,A满足以下条件:
1.A中有四的点, 五条线;
2.其中四条边能够成一个四边形,另一条边是该四边形的对角线;
如图:
很明显这是由两个有公共边的三元环构成的;
那么问题来了, 怎么求三元环呢?(n个顶点, m条边);
因为m=min(m, (n-1)n/2) 所以m≈n^2, n≈m½
一:暴力查询任意三个点, 看是否两两之间有连边;复杂度 O(n^3)≈O(m*m½);
二:按边查询;每次确定一个点a,找以他为端点的边,再找另一端点b的连边B,看B的另一端点c与a是否有连边, hash一下边;
复杂度 O(n*m)≈O(m*m½)(注意n^2是大于m的,所以二的复杂度是要比一低的);
在网上搜二有优化;在找到b点后,判断b的度与sqrt(m)的关系,degree[b]<=sqrt(m),就找与b的连点,否则找与a的连点, 这样复杂度看上去还是O(m*m½),但是实际要比O(m*m½)小,因为找的边数要小于m;
还有一点:这个题用long long;
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; int n, m; vector<int> G[maxn]; set<long long> se; int degree[maxn]; int vis[maxn], link[maxn]; int main(){ while(~scanf("%d%d", &n, &m)){ int u, v; se.clear(); for(int i=0; i<=n; i++){ G[i].clear(); vis[i]=0; degree[i]=0; link[i]=0; } for(int i=0; i<m; i++){ scanf("%d%d", &u, &v); degree[u]++; degree[v]++; G[u].push_back(v); G[v].push_back(u); se.insert((long long)u*maxn+v); se.insert((long long)v*maxn+u); } int limit=sqrt(m); long long ans=0; for(int i=1; i<=n; i++){ vis[i]=1; for(int j=0; j<G[i].size(); j++){ link[G[i][j]]=i; } ; for(int j=0; j<G[i].size(); j++){ int v=G[i][j]; long long cnt=0; if(vis[v]) continue; if(degree[v]<=limit){ for(int k=0; k<G[v].size(); k++){ if(link[G[v][k]]==i) cnt++; } } else{ for(int k=0; k<G[i].size(); k++){ if(se.find((long long)G[i][k]*maxn+v)!=se.end()) cnt++; } } ans+=(cnt-1)*cnt/2; } } printf("%lld\n", ans); } return 0; }