Tarjan算法 学习笔记
前排提示:先学习拓扑排序,再学习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算法 学习笔记的更多相关文章
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- 萌新学习图的强连通(Tarjan算法)笔记
--主要摘自北京大学暑期课<ACM/ICPC竞赛训练> 在有向图G中,如果任意两个不同顶点相互可达,则称该有向图是强连通的: 有向图G的极大强连通子图称为G的强连通分支: Tarjan算法 ...
- 算法学习笔记:Tarjan算法
在上一篇文章当中我们分享了强连通分量分解的一个经典算法Kosaraju算法,它的核心原理是通过将图翻转,以及两次递归来实现.今天介绍的算法名叫Tarjan,同样是一个很奇怪的名字,奇怪就对了,这也是以 ...
- Tarjan的学习笔记 求割边求割点
博主图论比较弱,搜了模版也不会用... 所以决心学习下tarjan算法. 割点和割边的概念不在赘述,tarjan能在线性时间复杂度内求出割边. 重要的概念:时间戟,就是一个全局变量clock记录访问结 ...
- 算法学习笔记——sort 和 qsort 提供的快速排序
这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...
随机推荐
- python写12306抢票
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 利用splinter写的一个手动过验证及自动抢票的例子, 大家可以自己扩展或者弄错窗体.web端. ...
- HTTP协议——详细版
一 HTTP协议简介 作为学习前端开发的开始,我们必须搞明白以下几件事 1.什么是互联网 互联网=物理连接介质+互联网协议 2.互联网建立的目的? 数据传输打破地域限制,否则 ...
- www.215wd.com
www.215wd.com 传奇销售系统 QQ:1479528000
- day5:isinstance&代码块&分支&while循环
1.判断类型 isinstance语法:用法一: isinstance(要判断的值,要判断的类型) 返回True 或者 False用法二: isinstance(要判断的值,(可能的类型1,可能的类型 ...
- 原来不只是fastjson,这个你每天都在用的类库也被爆过反序列化漏洞!
GitHub 15.8k Star 的Java工程师成神之路,不来了解一下吗! GitHub 15.8k Star 的Java工程师成神之路,真的不来了解一下吗! GitHub 15.8k Star ...
- centos7安装配置jdk1.8
第一步:下载JDK 链接:https://pan.baidu.com/s/1sXWzvL9Tv7HIDxDPIw70SQ 提取码:vpbi 第二步:通过远程连接工具将下载好的JDK8上传到li ...
- js 分享QQ、QQ空间、微信、微博
//分享QQ好友 function qq(title,url,pic) { var p = { url: 'http://test.qicheyitiao.com',/*获取URL,可加上来自分享到Q ...
- 简单实用的办公软件导航网站,IT经理必备工具
最近非常忙,因为公司上线了业财一体化系统.今天分享一个非常实用的办公软件导航网站,节省了我很多百度的时间. 快氪导航,让软件服务更简单. 一.办公软件导航 站长已经按照功能进行了分类:协同办公,流程审 ...
- antd4 源码学习 :表单
Evernote Export 首先.vue 的数据流是双向的,而 react 的数据流是单向的. 这意味着什么? 这意味着,vue 中,子组件可以用 emit 把数据更新传给父组件.而 react ...
- 轻量级分布式延时任务处理组件easyTask-L-入门篇
今天给大家介绍一款新武器.我自研的一个java组件easyTask-L.这个是做啥的呢?我之前研发了一款单机版本的easyTask,这次是要介绍另外一款easyTask-L.区别就是后者支持分布式环境 ...