tarjan系列算法代码小结
时间:2022-05-08
本文章向大家介绍tarjan系列算法代码小结,主要内容包括强联通分量、点双联通分量、边双联通分量、割顶、割边、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
个人使用,可能不是很详细
强联通分量
这里的dfn可以写成low
因为都是在栈中,只要保证该节点的low值不为本身即可
void tarjan(int now)
{
dfn[now]=low[now]=++tot;
s.push(now);
vis[now]=1;
for(int i=headE[now];i!=-1;i=E[i].nxt)
{
if(!dfn[E[i].v])
tarjan(E[i].v),low[now]=min(low[now],low[E[i].v]);
else if(vis[E[i].v])
low[now]=min(low[now],dfn[E[i].v]);
}
if(low[now]==dfn[now])
{
int h;
colornum++;
do
{
h=s.top();
color[h]=colornum;
sum[colornum]+=money[h];
vis[h]=0;
s.pop();
}while(h!=now);
}
}
点双联通分量
条件low[j]>=dfn[i]
栈的边界条件需要特殊判断
void tarjan(int now,int fa)
{
dfn[now]=low[now]=++tot;
s.push(now);
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
if(!dfn[edge[i].v]&&edge[i].v!=fa)
{
tarjan(edge[i].v,now);
low[now]=min(low[now],low[edge[i].v]);
if(low[edge[i].v]>=dfn[now])
{
memset(in,0,sizeof(in));//哪些在双联通分量里
memset(color,0,sizeof(color));
int h=0,cnt=0;
do
{
h=s.top();s.pop();
in[h]=1;
point[++cnt]=h;
}while(h!=edge[i].v);//warning
if(cnt<=1) continue;//必须构成环
in[now]=1;point[++cnt]=now;
if(MakeColor(now,1)==0)
for(int j=1;j<=cnt;j++)
ans[point[j]]=1;
}
}
if(edge[i].v!=fa) low[now]=min(low[now],dfn[edge[i].v]);
}
}
边双联通分量
记录一下父亲节点就好
void tarjan(int now,int fa)
{
dfn[now]=low[now]=++tot;
s.push(now);
vis[now]=1;
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
if(!dfn[edge[i].v]&&edge[i].v!=fa)
tarjan(edge[i].v,now),low[now]=min(low[now],low[edge[i].v]);
if(vis[edge[i].v]&&edge[i].v!=fa) low[now]=min(low[now],dfn[edge[i].v]);
}
if(dfn[now]==low[now])
{
int h=0;
colornum++;
do
{
h=s.top();
color[h]=colornum;
s.pop();
}while(h!=now);
}
}
割顶
条件low[j]>=dfn[i]
int tarjan(int now,int fa)
{
int ch=0;
dfn[now]=low[now]=++tot;
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
if(!dfn[edge[i].v])
{
tarjan(edge[i].v,fa);
low[now]=min(low[now],low[edge[i].v]);
if(low[edge[i].v]>=dfn[now]&&now!=fa) cut[now]=1;
if(now==fa) ch++;
}
low[now]=min(low[now],dfn[edge[i].v]);
}
if(now==fa&&ch>=2) cut[now]=1;
}
割边
条件low[v]>dfn[now]
void tarjan(int now,int fa)
{
dfn[now]=low[now]=++tot;
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
if(!dfn[edge[i].v])
{
deep[edge[i].v]=deep[now]+1;
f[edge[i].v]=now;
tarjan(edge[i].v,now);
low[now]=min(low[now],low[edge[i].v]);
if(low[edge[i].v]>dfn[now])
{
bridge[edge[i].v]=1;
ans++;
}
}
else if(edge[i].v!=fa) low[now]=min(low[now],dfn[edge[i].v]);
}
}
- webpack学习(七)打包压缩图片
- POJ1275 Cashier Employment(差分约束)
- REDIS操作命令小结
- Java发送邮件工具类
- javascript 变量、作用域和内存问题
- 1726: [Usaco2006 Nov]Roadblocks第二短路
- vue小白快速入门
- 算法模板——线段树9(区间加+区间求和+区间方和)
- 1709: [Usaco2007 Oct]Super Paintball超级弹珠
- 2015: [Usaco2010 Feb]Chocolate Giving
- 2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛
- 2020: [Usaco2010 Jan]Buying Feed, II
- 2102: [Usaco2010 Dec]The Trough Game
- 洛谷P3707 [SDOI2017]相关分析(线段树)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法