Counting Stars HDU - 6184(三元环判定)

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;
}



猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/80589691
今日推荐