算法学自 BYVoid

https://www.byvoid.com/zhs/blog/scc-tarjan/

这个写得很清楚了

当然 你可能不这么认为

而且 如果是让我 一开始就从这个博客 学 tarjan 缩点

估计我也会觉得 很难懂

我猜是 博客看多了 有了些基础

在看这一篇的时候懂了

就觉得 是这篇比较好懂

(事实上人家本来写得就可以嘛)

我想到了 班主任的一句话

量的积累 才有质的变化

GeneralLiu

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]);

}

  缩点

}

两个例题

luogu1

luogu2

输出要求不同,

笔者建议 独立体会

下面的 代码 大同小异

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的更多相关文章

  1. POJ-3352 Road Construction,tarjan缩点求边双连通!

    Road Construction 本来不想做这个题,下午总结的时候发现自己花了一周的时间学连通图却连什么是边双连通不清楚,于是百度了一下相关内容,原来就是一个点到另一个至少有两条不同的路. 题意:给 ...

  2. Tarjan缩点求入度为零的点的个数问题

    Description: 一堆人需要联系,但如果x 可以联系 y,你联系了x就不用联系y了,你联系一个人都会有固定的花费,问你最小联系多少人,和最小花费 Solution: Tarjan缩点,求出缩点 ...

  3. HDU 4612 Warm up tarjan缩环+求最长链

    Warm up Problem Description   N planets are connected by M bidirectional channels that allow instant ...

  4. BZOJ5450: 轰炸(水题,Tarjan缩点求最长路)

    5450: 轰炸 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 43  Solved:18[Submit][Status][Discuss] Desc ...

  5. Grouping ZOJ - 3795 (tarjan缩点求最长路)

    题目链接:https://cn.vjudge.net/problem/ZOJ-3795 题目大意:给你n个人,m个关系, 让你对这个n个人进行分组,要求:尽可能的分组最少,然后每个组里面的人都没有关系 ...

  6. 【Tarjan缩点】PO3352 Road Construction

    Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 12532   Accepted: 630 ...

  7. POJ2533&&SP1799 The Bottom of a Graph(tarjan+缩点)

    POJ2553 SP1799 我们知道单独一个强连通分量中的所有点是满足题目要求的 但如果它连出去到了其他点那里,要么成为新的强连通分量,要么失去原有的符合题目要求的性质 所以只需tarjan缩点求出 ...

  8. tarjan算法求scc & 缩点

    前置知识 图的遍历(dfs) 强连通&强连通分量 对于有向图G中的任意两个顶点u和v存在u->v的一条路径,同时也存在v->u的路径,我们则称这两个顶点强连通.以此类推,强连通分量 ...

  9. 间谍网络——tarjan求SCC

    洛谷传送门 看着这道题给人感觉就是tarjan求SCC,然而还得判断是否能控制全部间谍,这就得先从可以贿赂的点dfs一遍. 如果没有全部被标记了,就输出NO,再从没被标记的点里找最小的标号. 如果全被 ...

随机推荐

  1. error: stray '\343' in program 问题解决

          当我们从网上copy一段代码后,总会出现这个问题.博主在Arduino环境中也出现了,so,这个问题应该是C语言和C++编译器中才会出现的. test_int:19: error: str ...

  2. POJ 1739 Tony's Tour (插头DP,轮廓线DP)

    题意:给一个n*m的矩阵,其中#是障碍格子,其他则是必走的格子,问从左下角的格子走到右下角的格子有多少种方式. 思路: 注意有可能答案是0,就是障碍格子阻挡住了去路. 插头DP有两种比较常见的表示连通 ...

  3. -[UPAInitViewController startAPPay] in libUPAPayPlugin.a(UPAInitViewController.o)

    问题 Undefined symbols for architecture arm64: "_PKPaymentNetworkChinaUnionPay", referenced ...

  4. leetcode_1048. Longest String Chain_[DP,动态规划,记忆化搜索]

    1048. Longest String Chain https://leetcode.com/problems/longest-string-chain/ Let's say word1 is a ...

  5. SSave ALAsset image to disk fast on iOS

    I am using ALAsset to retrieve images like that: [[asset defaultRepresentation] fullResolutionImage] ...

  6. C01 C语言基础

    目录 C语言简史及特点 C语言开发环境 C语言程序结构 C语言基本输入输出函数 编译 软件类型 C语言简要及特点 什么是计算机语言 计算机语言是用于人与计算机之间通讯的语言. 计算机遵照接收到的计算机 ...

  7. Ubuntu12.04安装Chrome浏览器,并添加到左侧的启动栏

    在google官网下载google chrome deb包,有32位和64位之分: 怎么判断系统是32位还是64位的,可以用以下代码: ; int *p = &a; printf(" ...

  8. web资源持续更新----20150213

    响应式设计创意收集网站:http://mediaqueri.es css禅意花园 http://www.csszengarden.com/

  9. PAT 乙级 1011

    题目 题目地址:PAT 乙级 1011 思路 这道题的比较坑的地方在于给定数据的范围 int 类型的数据大小是[-2^31 , 2^31 -1] 即 [-2147483648,2147483647] ...

  10. PHP 把字符转换为 HTML 实体 - htmlentities() 函数

    定义和用法 htmlentities() 函数把字符转换为 HTML 实体. 语法 htmlentities(string,quotestyle,character-set) 参数 描述 string ...