前排提示:先学习拓扑排序,再学习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. shell进阶篇之数组应用案例

    数组中可以存放多个值. Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小. 与大部分编程语言类似,数组元素的下标由0开始. Shell 数组用括号来表示,元素用"空格 ...

  2. 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!

    Python函数定义.匿名函数.嵌套函数.闭包.装饰器 目录 Python函数定义.匿名函数.嵌套函数.闭包.装饰器 函数核心理解 1. 函数定义 2. 嵌套函数 2.1 作用 2.2 函数变量作用域 ...

  3. 数据可视化之powerBI技巧(十八)Power BI动态技巧:动态显示列和度量值

    今天分享一个可视化小技巧,如何在PowerBI的表格中动态显示需要的列? 就是这样的效果, 也就是根据切片器的筛选,来显示需要的列,做起来很简单,步骤如下: 01 逆透视表 进入Powerquery编 ...

  4. 临时解决GitHub的raw.githubusercontent.com无法连接问题

    http://qjzd.net:3000/topic/5e48cc33dcf06d6a181ffb81 查询真实IP 通过IPAddress.com首页,输入raw.githubusercontent ...

  5. 面试软件测试工程师——盘点HR的那些黑话

    当疫情过后,应该有很多测试实习生寻找测试岗或者已从业测试岗的群体进行跳槽:最近也收到很多测试新生的咨询,在这里简单分享一下!老铁们走起!今天在这里就简单做跟大家聊一聊面试过程中你与面试官/HR聊天过程 ...

  6. Python Ethical Hacking - BACKDOORS(8)

    Cross-platform hacking All programs we wrote are pure python programs They do not rely on OS-specifi ...

  7. 题解 洛谷 P2287 [USACO07NOV]Sunscreen G

    原题 传送门 有C个奶牛去晒太阳 (1 <=C <= 2500),每个奶牛各自能够忍受的阳光强度有一个最小值和一个最大值(minSPFi and maxSPFi),太大就晒伤了,太小奶牛没 ...

  8. antd踩坑:value.locale is not a function

    这个问题来源于日期选择器 RangerPicker 的特殊情况. <Col span={7} key={9}> <FormItem label="投运时间" {. ...

  9. 题解 UVA501 【Black Box】

    思路与中位数一题,解决方案比较像,使用对顶堆来解决. 具体实现为,使用两个堆,大根堆维护较小的值,小根堆维护较大的值,即小根堆的堆顶是较大的数中最小的,大根堆的堆顶是较小的数中最大的. 将大于大根堆堆 ...

  10. WebView in ScrollView:View not displayed because it is too large to fit into a software layer

    报错信息 W/View: WebView not displayed because it is too large to fit into a software layer (or drawing ...