hdu6184 Counting Stars(三元环计数)

题目

hdu6184 Counting Stars(三元环计数)_第1张图片

思路来源

https://www.cnblogs.com/jiachinzhao/p/7474761.html

https://www.cnblogs.com/Khada-Jhin/p/10143074.html

题解

三元环的题,可参考bzoj3498

本来看了题解,也没大懂,好在归神讲了讲

只会暴力check这一种做法

对于for(u=1;u<=n;++u)来讲

①考虑所有u为度数>sqrt(m)的点,

(1)如果v为度数>sqrt(m)的点,就去for循环u,

枚举的是形如u-vv这样的边,复杂度O(m),

由于u这种点的个数不超过sqrt(m),所以复杂度是O(m*sqrt(m))的

(2)如果v为度数

枚举的是形如u-v这样的边,O(m)

这样由于v的度数不超过sqrt(m),保证了v的点的个数是O(sqrt(m))的,

所以复杂度是O(m*sqrt(m))的

②考虑所有u为度数

(1)如果v为度数>sqrt(m)的点,就去for循环u的点,

由于u的度数不超过sqrt(m),枚举的是形如u-v这样的边,所以复杂度是O(m*sqrt(m))的

(2)如果v为度数

由于v的度数不超过sqrt(m),枚举的是形如u-v这样的边,所以复杂度是O(m*sqrt(m))的

综上,均摊复杂度O(m*sqrt(m)),但常数较大

简言之,就是对于每个固定的u,v的度数小的话就检查v内的点,否则检查u内的点

由于枚举的是u-v,且v-u不会被重复枚举,所以根据交边C(cnt,2)统计即可

 

 

代码

#include
#include
#include
#include
#include 
#include
using namespace std;
#define pb push_back
typedef long long ll;
const int N=1e5+10;
setq;
vectore[N];
bool vis[N];
int n,m,u,v,sz,deg[N],vi[N];
ll ans;
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n;++i)
		e[i].clear(),deg[i]=vis[i]=vi[i]=0;
		q.clear();
		ans=0;
		sz=sqrt(m+0.5);
		for(int i=1;i<=m;++i)
		{
			scanf("%d%d",&u,&v);
			e[u].pb(v);e[v].pb(u); 
			deg[u]++;deg[v]++;
			q.insert(v+1ll*u*n);
			q.insert(u+1ll*v*n);
		}
		for(int u=1;u<=n;++u)
		{
			vis[u]=1;
			for(auto v:e[u])
			vi[v]=u;
			for(auto v:e[u])//对于每对(u,v)的边 统计位于多少个三元环内 
			{
				if(vis[v])continue;
				int cnt=0;
				if(deg[v]<=sz)
				{
					for(auto vv:e[v])
					if(vi[vv]==u)cnt++;
				}
				else
				{
					for(auto vv:e[u])
					if(q.find(vv+1ll*n*v)!=q.end())cnt++;
				}
				ans+=1ll*cnt*(cnt-1)/2;
			}
			
		}
		printf("%lld\n",ans);
	}
	return 0;
} 

 

你可能感兴趣的:(#,图论基础,三元环,图论)