前排提示:先学习拓扑排序,再学习Tarjan有奇效。

--------------------------

Tarjan算法一般用于有向图里强连通分量的缩点。

强连通分量:有向图里能够互相到达的点的集合。(大概是这么个意思,自己意会)

因为能够互相到达,所以宏观上我们可以把它们看成一个点,边权也相应的加起来即可。

下面是Tarjan过程的代码解释:

我们开两个数组,分别为dfn[]和low[]。dfn表示此点的时间戳,low表示最早的时间戳。(即进入某一个环最早的时间戳)

遇到一个没有记录过的点,就把它扔到栈里,不停dfs,直到dfn[]==low[],即某一个环已经遍历完了,我们就弹栈,将这一个环合并。

代码如下:

void tarjan(int now)
{
dfn[now]=low[now]=++cnt;
st[++top]=now;
vis[now]=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now])
{
tot++;
while(st[top+]!=now)
{
pos[st[top]]=tot;
sum[tot]+=val[st[top]];
vis[st[top--]]=;
}
}
}

配合拓扑排序,一张新的有向无环图就构造了出来。

-------------------------------------------------------------------------------------

【模板】 缩点

给定一个含有n个点m条边的有向图每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

第一行两个整数,为$n$,$m$。

第二行到第$m+1$行有每行有3个整数,分别为$u,v,d$,表示$u\rightarrow v$有一条长度为$d$的边。

输出格式:一行结果。

-------------------------------------------------

Tarjan模板题,只不过加了一点小DP,记忆化搜索即可。注意的地方就是拓扑排序后的重新建图。

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
int cnt,dfn[maxn],vis[maxn],low[maxn];
int f[maxn],sum[maxn],ans;
int jishu,head[];
int top,st[maxn],pos[maxn],tot;
int n,m,x[maxn],y[maxn],val[maxn];
struct node
{
int next,to;
}edge[];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++jishu].next=head[from];
edge[jishu].to=to;
head[from]=jishu;
}
void tarjan(int now)
{
dfn[now]=low[now]=++cnt;
st[++top]=now;
vis[now]=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now])
{
tot++;
while(st[top+]!=now)
{
pos[st[top]]=tot;
sum[tot]+=val[st[top]];
vis[st[top--]]=;
}
}
}
void search(int x)
{
if (f[x]) return;
f[x]=sum[x];
int maxx=;
for (int i=head[x];i;i=edge[i].next)
{
int to=edge[i].to;
if (!f[to]) search(to);
maxx=max(maxx,f[to]);
}
f[x]+=maxx;
}
void clear()
{
jishu=;
memset(edge,,sizeof(edge));
memset(head,,sizeof(head));
}
int main()
{
n=read(),m=read();
for (int i=;i<=n;i++) val[i]=read();
for (int i=;i<=m;i++)
{
x[i]=read(),y[i]=read();
add(x[i],y[i]);
}
for (int i=;i<=n;i++) if (!dfn[i]) tarjan(i);
clear();
for (int i=;i<=m;i++) if (pos[x[i]]!=pos[y[i]]) add(pos[x[i]],pos[y[i]]);
for (int i=;i<=n;i++) search(i),ans=max(ans,f[i]);
printf("%d\n",ans);
return ;
}

另,如果是无向图缩点,一定要加上这句话:

if (edge[i].to==fa) continue;

【模板】割点

给定一个含有n个点m条边的无向图,求图的割点。

------------------------------------------

割点是指去掉这个点整个图便不连通的点。

我们可以同样用Tarjan算法,建立一颗搜索树。

如果此点为根节点,则判断是否有>=2棵子树。如果存在,那么此点为割点。

对于非根节点,如果low[v]>=dfn[u]($u\rightarrow v$)那么u点为割点(因为从u点开始无论怎么走都不可能回到原来的点了)。

思路还是比较清晰的,直接放代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
int head[],jishu;
int dfn[maxn],low[maxn],cnt;
int n,m,ans;
bool cut[maxn];
struct node
{
int next,to;
}edge[];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++jishu].next=head[from];
edge[jishu].to=to;
head[from]=jishu;
}
void tarjan(int now,int fa)
{
dfn[now]=low[now]=++cnt;
int child=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]){
tarjan(to,fa);
low[now]=min(low[now],low[to]);
if (low[to]>=dfn[now]&&now!=fa) cut[now]=;
if (now==fa) child++;
}
low[now]=min(low[now],dfn[to]);
}
if (child>=&&now==fa) cut[now]=;
}
int main()
{
n=read(),m=read();
for (int i=;i<=m;i++)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
for (int i=;i<=n;i++) if (!dfn[i]) tarjan(i,i);
for (int i=;i<=n;i++) if (cut[i]) ans++;
printf("%d\n",ans);
for (int i=;i<=n;i++) if (cut[i]) printf("%d ",i);
return ;
}

Tarjan算法 学习笔记的更多相关文章

  1. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  2. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  3. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  4. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  5. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  6. 萌新学习图的强连通(Tarjan算法)笔记

    --主要摘自北京大学暑期课<ACM/ICPC竞赛训练> 在有向图G中,如果任意两个不同顶点相互可达,则称该有向图是强连通的: 有向图G的极大强连通子图称为G的强连通分支: Tarjan算法 ...

  7. 算法学习笔记:Tarjan算法

    在上一篇文章当中我们分享了强连通分量分解的一个经典算法Kosaraju算法,它的核心原理是通过将图翻转,以及两次递归来实现.今天介绍的算法名叫Tarjan,同样是一个很奇怪的名字,奇怪就对了,这也是以 ...

  8. Tarjan的学习笔记 求割边求割点

    博主图论比较弱,搜了模版也不会用... 所以决心学习下tarjan算法. 割点和割边的概念不在赘述,tarjan能在线性时间复杂度内求出割边. 重要的概念:时间戟,就是一个全局变量clock记录访问结 ...

  9. 算法学习笔记——sort 和 qsort 提供的快速排序

    这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...

随机推荐

  1. python数据处理(三)之处理pdf文件

    代码以及资料 https://github.com/jackiekazil/data-wrangling 1.前言 尽可能地寻找可以替代pdf格式的数据 2.解析pdf的编程方法 安装slate pi ...

  2. 数据可视化之powerBI基础(十六)PowerQuery的这个小功能,让你轻松发现数据质量问题

    https://zhuanlan.zhihu.com/p/64418072 源数据常常包含各种差错值,为了进行下一步的分析,我们必须先找出并更正这些差错,做这些工作几乎不会有什么快乐感可言,但却往往需 ...

  3. hihoCoder 1114 小Hi小Ho的惊天大作战:扫雷·一 最详细的解题报告

    题目来源:小Hi小Ho的惊天大作战:扫雷·一 解题思路:因为只要确定了第一个是否有地雷就可以推算出后面是否有地雷(要么为0,要么为1,如果不是这两个值就说明这个方案行不通),如果两种可能中有一种成功, ...

  4. 动手实现一个简单的 rpc 框架到入门 grpc (下)

    之前手动实现了一次简陋的 rpc 调用,为了简单使用了 json 编码信息,其实这是非常不可靠的,go 中 json 解析会有一些问题,比如整数会变成浮点数,而且 json 字符串比较占空间. gRP ...

  5. package.json中dependencies和devDependencies区别

    package.json中dependencies和devDependencies区别 dependencies: 应用能够正常运行依赖的包.用户发布环境,依赖的包不仅开发环境能够使用,生产环境也能使 ...

  6. StringBuilder和 String的区别?

    String在进行运算时(如赋值.拼接等)会产生一个新的实例,而 StringBuilder则不会.所以在大 量字符串拼接或频繁对某一字符串进行操作时最好使用 StringBuilder,不要使用 S ...

  7. Flutter 实现酷炫的3D效果

    老孟导读:此文讲解3个酷炫的3D动画效果. 下面是要实现的效果: Flutter 中3D效果是通过 Transform 组件实现的,没有变换效果的实现: class TransformDemo ext ...

  8. Spring事务处理时自我调用

    1.预备知识 aop概念请参考[http://www.iteye.com/topic/1122401]和[http://jinnianshilongnian.iteye.com/blog/141859 ...

  9. web自动化 -- HTMLreport(二)测试报告输出内容居左对齐

    一.需求痛点 1.报告输出内容是居中对齐,很难看 2.我们希望输出内容是居左对齐 3.痛点截图 二.解决办法 1.原因分析 HTMLreport的内容对齐方式,自然是修改HTMLreport的内容了 ...

  10. 解决react使用antd table组件固定表头后,表头和表体列不对齐以及配置fixed固定左右侧后行高度不对齐

    一.固定表头后表体列和表头不对齐 此问题可能在antd3.24.0版本之前都存在,反正3.16.2版本是存在这个问题的,如果是3.24.0之前的版本估计只能通过修改css样式解决. 按照官网说的: 1 ...