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,再从没被标记的点里找最小的标号. 如果全被 ...
随机推荐
- Android 权限的实现
1. 权限 每个程序在安装时都有建立一个系统ID,如app_15,用以保护数据不被其它应用获取.Android根据不同的用户和组,分配不同权限,比如访问SD卡,访问网络等等.底层映射为Linux ...
- (转)VIM 一键自动添加文件头注释
通过修改VIM的配置文件.vimrc可以让Vim(gvim)支持自动添加作者信息,具体代码如下: "进行版权声明的设置 "添加或更新头 map <F4> :call T ...
- [总结].net操作MongoDb通用基础类1:
public class MongoDBHelper { //定义Mongo服务 private MongoServer mongo = null; //获取databaseName对应的数据库,不存 ...
- shell框架
#!/bin/bash#注释#注释#环境变量相关,如下PATH=/sbin:/bin:/usr/bin:/usr/sbin #引入库函数,如下,类似于c语言的#include "*.h&qu ...
- Linux中配置系统参数
[root@localhost ~]# vim /etc/security/limits.conf root soft nofile 65535root hard nofile 65535* soft ...
- 如何用JavaScript判断前端应用运行环境(移动平台还是桌面环境)
我们部署在某些云平台或者Web服务器上的前端应用,既可以用PC端浏览器访问,也可以用手机上的浏览器访问. 在前端应用里,有时候我们需要根据运行环境的不同做出对应处理.比如下面这段逻辑,如果判断出应用当 ...
- poj3264 划分树
题意: 给定一个序列,询问区间中最大数减去最小数的结果 和2104差不多, 代码贴过来就OK了 #include <iostream> #include <algorithm> ...
- Linux命令基础操作--vim 归档 压缩 分区 格式化 挂载 Innode
1 将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/1.txt(覆盖) 使用 cat命令将查看的文件合并输出到/1.txt 这里的关键:定位到文件,如果后面加上/后被认为是目录 分为两步,先 ...
- CPP-基础:char、BYTE、byte
一,C++语言的内建类型中没“BYTE”这么个类型.BYTE是WINDOWS Platform SDK中windef.h里面定义的:typedef unsigned char BYTE; 二,char ...
- gdb插件使用方法
0x00 peda peda 安装: git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda ...