【洛谷 P1989】 无向图三元环计数【三元环计数】

67 篇文章 0 订阅

在这里插入图片描述

在这里插入图片描述


解题思路

我们考虑给所有的边一个方向。具体的,如果一条边两个端点的度数不一样,则由度数较小的点连向度数较大的点,否则由编号较小的点连向编号较大的点。称小的点优先级比大的点高

即:原图中的环 ( u , v ) , ( v , w ) , ( u , w ) (u,v),(v,w),(u,w) (u,v),(v,w),(u,w)(不妨设u优先级比v高,v优先级比w高)在新图上表现为 ( u − > v , v − > w , u − > w ) (u->v,v->w,u->w) (u>v,v>w,u>w)

手推一下,这样的图是有向无环的。原图中的三元环一定与对应有向图中所有形如 < u → v > , < u → w > , < v → w > <u→v>,<u→w>,<v→w> <uv>,<uw>,<vw>的子图一一对应,我们只需要枚举 u 的出边,再枚举 v 的出边,然后检查 w 是不是 uu 指向的点即可。


代码

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;

int n,m,kk,d[100010],u[200010],v[200010],head[200010];
ll ans;

struct c {
	int x,next;
} a[200010];

void add(int x,int y) {
	a[++kk].x=y;
	a[kk].next=head[x];
	head[x]=kk;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u[i],&v[i]);
		d[u[i]]++,d[v[i]]++;
	}
	for(int i=1;i<=m;i++)
	{
		if((d[u[i]]>d[v[i]])||(d[u[i]]==d[v[i]]&&u[i]>v[i]))
		swap(u[i],v[i]);
		add(u[i],v[i]);
	}
	memset(v,0,sizeof(v));
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j;j=a[j].next)
			v[a[j].x]=1;
		for(int j=head[i];j;j=a[j].next)
		{
			int y=a[j].x;
			for(int k=head[y];k;k=a[k].next)
				if(v[a[k].x])ans++;
		}
		for(int j=head[i];j;j=a[j].next)
			v[a[j].x]=0;
	}
	printf("%lld",ans); 
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值