tarjan 缩点 求 scc
算法学自 BYVoid
https://www.byvoid.com/zhs/blog/scc-tarjan/
这个写得很清楚了
当然 你可能不这么认为
而且 如果是让我 一开始就从这个博客 学 tarjan 缩点
估计我也会觉得 很难懂
我猜是 博客看多了 有了些基础
在看这一篇的时候懂了
就觉得 是这篇比较好懂
(事实上人家本来写得就可以嘛)
我想到了 班主任的一句话
量的积累 才有质的变化
tarjan 缩点 求 scc(strongly connected components)
有向图 强连通分量
首先 给自己 刷个广告
tarjan 是基于 dfs树 的算法
我觉得 dfs树 上的一些 术语有必要知道 一下
所以, 看我 博客
还有, 就是 ,两个数组 dfn[] , low[]
分别为 i的时间戳 , i能最早追溯到的时间戳
这个比较难理解
但非常重要
因为 tarjan 发明的 求 割点、割边 的算法
也要活用到 这两个数组
(其实不用怕 tarjan ,这不过是个帅哥 的名字 罢了)

说说我的个人理解
dfn [ i ] 是程序第几次 dfs 到 节点 i
所以起名叫 dfn ( dfs 的 第 n 次执行 ,n ∈ [ 1 , MAXN ] );
low [ i ] 是 dfs 过程中 有时会
遇到回到 之前 节点的 路径 ( 之前 是指先前 dfs 到 的 点 )
那么 节点 i 就能 沿着 这条路 返回 之前的点
low [ i ] 就是 i { [ 能返回的 ( dfn值最小的 ) 点 ] 的dfn值 }
额 。理不理解都往下看吧 毕竟 量的积累 还是很有必要的
每次dfs(点u){
dfn[u] = 进入 dfs() 函数的次数 (自己定义一个时间戳记录 如 timee)
枚举与其相邻的点v{
如果 没有 访问过点v { ( 就是dfs树上的树边 )
dfs(v);
如果 v 能追溯 到 比“u 追溯到的最早的点” 更早的点;
那么 u 就能 通过 v 来追溯到 那个点;
low[u]=min(low[u],low[v]);
}
如果 访问过点v && v在栈中
low[u]=min(low[u],dfn[v]);
}
缩点
}
两个例题
输出要求不同,
笔者建议 独立体会
下面的 代码 大同小异
1
#include<iostream>
#include<stack>
#include <cstring>
using namespace std;
int m,ans,bbk[],bk,b[],head[],cnt,dfn[],low[],n;
stack<int>zz;
bool ru[];
struct aa{
int to,next;
}e[];
void add(int x, int y)
{
e[cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt++;
} /*void add(int from,int to){
e[++cnt]=(aa){to,head[from]};
head[from]=cnt;
}*/
void dfs(int k){
dfn[k]=low[k]= ++cnt;
b[k]=;
zz.push(k);
int j;
for(int i=head[k];i!=-;i=e[i].next){
j=e[i].to;
if(!dfn[j]){
dfs(j);
low[k]=min(low[k],low[j]);
}
else if(b[j]&&dfn[j]<low[k])low[k]=dfn[j];
}
if(dfn[k]==low[k]){
bk++;
do{
j=zz.top();
zz.pop();
b[j]=;
bbk[j]=bk;
}while(j!=k);
}
}
int main(){
cin>>n;
memset(head, -, sizeof(head));
for(int x,i=;i<=n;i++){
cin>>x;
while(x){
add(i,x);
cin>>x;
}
}
cnt=;
for(int i=;i<=n;i++)
if(!dfn[i])
dfs(i);
for(int i=;i<=n;i++)
for(int y,j=head[i];j!=-;j=e[j].next){
y=e[j].to;
if(bbk[y]!=bbk[i])ru[bbk[y]]=;
}
for(int i=;i<=bk;i++)
if(!ru[i])
ans++;
cout<<ans;
return ;
}
2
#include<iostream>
#include<stack>
using namespace std;
int m,ans,bbk[],bk,b[],head[],cnt,dfn[],low[],n;
stack<int>zz;
struct aa{
int to,next;
}e[];
void add(int from,int to){
e[++cnt]=(aa){to,head[from]};
head[from]=cnt;
}
void dfs(int k){
dfn[k]=low[k]= ++cnt;
b[k]=;
zz.push(k);
int j;
for(int i=head[k];i;i=e[i].next){
j=e[i].to;
if(!dfn[j]){
dfs(j);
low[k]=min(low[k],low[j]);
}
else if(b[j]&&dfn[j]<low[k])low[k]=dfn[j];
}
if(dfn[k]==low[k]){
bk++;
do{
j=zz.top();
zz.pop();
b[j]=;
bbk[bk]++;
}while(j!=k);
}
}
int main(){
cin>>n>>m;
for(int x,y,i=;i<=m;i++){
cin>>x>>y;
add(x,y);
}
cnt=;
for(int i=;i<=n;i++)
if(!dfn[i])
dfs(i);
for(int i=;i<=bk;i++)
if(bbk[i]>)
ans++;
cout<<ans;
return ;
}
tarjan 缩点 求 scc的更多相关文章
- POJ-3352 Road Construction,tarjan缩点求边双连通!
Road Construction 本来不想做这个题,下午总结的时候发现自己花了一周的时间学连通图却连什么是边双连通不清楚,于是百度了一下相关内容,原来就是一个点到另一个至少有两条不同的路. 题意:给 ...
- Tarjan缩点求入度为零的点的个数问题
Description: 一堆人需要联系,但如果x 可以联系 y,你联系了x就不用联系y了,你联系一个人都会有固定的花费,问你最小联系多少人,和最小花费 Solution: Tarjan缩点,求出缩点 ...
- HDU 4612 Warm up tarjan缩环+求最长链
Warm up Problem Description N planets are connected by M bidirectional channels that allow instant ...
- BZOJ5450: 轰炸(水题,Tarjan缩点求最长路)
5450: 轰炸 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 43 Solved:18[Submit][Status][Discuss] Desc ...
- Grouping ZOJ - 3795 (tarjan缩点求最长路)
题目链接:https://cn.vjudge.net/problem/ZOJ-3795 题目大意:给你n个人,m个关系, 让你对这个n个人进行分组,要求:尽可能的分组最少,然后每个组里面的人都没有关系 ...
- 【Tarjan缩点】PO3352 Road Construction
Road Construction Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 12532 Accepted: 630 ...
- POJ2533&&SP1799 The Bottom of a Graph(tarjan+缩点)
POJ2553 SP1799 我们知道单独一个强连通分量中的所有点是满足题目要求的 但如果它连出去到了其他点那里,要么成为新的强连通分量,要么失去原有的符合题目要求的性质 所以只需tarjan缩点求出 ...
- tarjan算法求scc & 缩点
前置知识 图的遍历(dfs) 强连通&强连通分量 对于有向图G中的任意两个顶点u和v存在u->v的一条路径,同时也存在v->u的路径,我们则称这两个顶点强连通.以此类推,强连通分量 ...
- 间谍网络——tarjan求SCC
洛谷传送门 看着这道题给人感觉就是tarjan求SCC,然而还得判断是否能控制全部间谍,这就得先从可以贿赂的点dfs一遍. 如果没有全部被标记了,就输出NO,再从没被标记的点里找最小的标号. 如果全被 ...
随机推荐
- KVC/KVO 本质
KVO 的实现原理 KVO是关于runtime机制实现的 当某个类的对象属性第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法.派生类 ...
- python super详解
一.super() 的入门使用 - 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能, 这时,我们就需要调用父类的方法了,可通过使用 super 来实 ...
- java httpclient 跳过证书验证
import java.io.IOException;import java.net.InetAddress;import java.net.Socket;import java.net.Unknow ...
- gvim -- 跳转命令,查找格式,正则
1.跳转命令 ‘w'单词前进,'b'单词后退,'e'单词前进,‘ge’单词后退,存在单词词首词尾区别,'W''B''E''gE'将不以单词区分,以空格区分 ‘$’行尾,'^'非空白行首,'0'行首 ‘ ...
- SQL2005中使用backup、restore来备份和恢复数据库
在SQL2005数据库中利用SQL语句进行数据备份与还原: 备份backup:backup database 数据库名称 tO disk = 备份路径例:BACKUP DATABASE test TO ...
- js 获取当前URL信息
document.location 这个对象包含了当前URL的信息 location.host 获取port号 location.hostname 设置或获取主机名称 location.href 设置 ...
- Vue 前端面试题[转]
https://mp.weixin.qq.com/s/Uxhx2dJ1Xbm6N3Gl7wNZNw Vue 前端面试题 游荡de蝌蚪 前端开发 1周前 作者:游荡de蝌蚪 https://segmen ...
- webStorm Ctrl+s 自动格式化 然后 保存 用宏命令
使用WebStorm的Macros宏指令,实现保存的同时格式化代码,并跳至行尾 https://blog.csdn.net/gyz718/article/details/70556188
- python小括号( )与中括号 [ ]
在python中小括号()表示的是tuple元组数据类型,元组是一种不可变序列. >>> a = (1,2,3) >>> a (1, 2, 3) >>& ...
- Use-After-Free
0x00 UAF利用原理 uaf漏洞产生的主要原因是释放了一个堆块后,并没有将该指针置为NULL,这样导致该指针处于悬空的状态(这个指针可以称为恶性迷途指针),同样被释放的内存如果被恶意构造数据,就有 ...