三元环计数
虽然说这是图上计数的问题,但是方法还是非常简单的。
我们只考虑无向图的情况。有向图只需要在无向图的环求出之后验证一下就行了。
我们不妨假设图中的点标号为 。然后我们对这个无向图的边进行定向,从度数小的点连向度数大的点,如果度数相同就从标号小的点连向标号大的点。容易发现这是个偏序关系,连出来的一定是 DAG。
然后暴力枚举就完事了。
我们的做法是枚举点 的所有出边并打上标记,然后对每个被打标记的点看是否能一步到达另外一个带标记的点。
看上去就是简单的暴力。但我们接下来证明复杂度是 。
考虑三元环 ,不妨设它在 DAG 上的形式为 (有向边)。容易发现每个三元环只会在 处被枚举一次。
另外容易发现前面枚出边的复杂度是线性的,关键在于枚举打标记的点的复杂度。
记点 的出度是 ,那么很明显统计次数就是 。我们要尝试算出来这个式子。
考虑对每个点 在图上的总的度数 进行分类讨论。
比如说我们给定一个 :
- 。
- ,又有 ,故 。
很明显取 最优,此时有 。
综上统计的时间复杂度是 。
code:
int n,m,cnt,ans,h[maxn],deg[maxn],vis[maxn];
struct edge{int to,nxt;}e[maxm];
inline void addedge(int u,int v)
{
e[++cnt]=(edge){v,h[u]};
h[u]=cnt;
}
struct edg{int u,v;}ed[maxm];
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
ed[i]=(edg){u,v};
deg[u]++;deg[v]++;
}
for(int i=1;i<=m;i++)
{
int nowu=ed[i].u,nowv=ed[i].v;
if(deg[nowu]<deg[nowv]||(deg[nowu]==deg[nowv]&&nowu<nowv))
addedge(nowu,nowv);
else addedge(nowv,nowu);
}
for(int u=1;u<=n;u++)
{
for(int i=h[u];i;i=e[i].nxt)vis[e[i].to]=u;
for(int i=h[u];i;i=e[i].nxt)
{
int p=e[i].to;
for(int v=h[p];v;v=e[v].nxt)
if(vis[e[v].to]==u)
ans++;
}
}
printf("%d\n",ans);
return 0;
}
作者:pjykk
出处:https://www.cnblogs.com/pjykk/p/16500744.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2019-07-21 数论整理(代码篇)