反过来调过去,我还是感觉没学明白缩点

  • 讲一个有向图中的所有强连通分量缩成一个点后,构成的新图是一个DAG。
  • 一个点所在的强连通分量一定被该点所在DFS搜索树所包含
  • 树上的边大致分为:树枝边,前向边(从上往下指),后向边(从下往上指),横叉变。其中前向边肉眼可见地没什么卵用

接下来开始算法流程。

  • tarjan的精髓如上次所说,在于DFS搜索树,在DFS搜索树中强连通分量以怎样形式存在是关键问题。对于x,存在祖宗y,从x出发可经过横叉边,返祖边,后向边到达y,则x,y属于同一强连通分量。操作中记录最小 y 为:low(x)=dfn(y)。(其中单点也算强连通块)如果有一个dfn_x=low_x ,那么就是说 x 在一个新的强连通块里,同理,low_x的初始也就是dfn_x。
  • 我们用一个栈来维护 已经被遍历过的、还未确定隶属哪个强连通分量的 点,在该栈中越靠栈顶DFS序越靠后(是栈底元素的后代)。
  • 关于low_x的求法、更新。考虑如何求low_x:low_x 可能被更新,当且仅当x连出了一条树枝边,横叉边或后向边。设该边连向点 v

1.  树枝边: low_x= min(low_x,low_v) v 到达的点x一定可以到达,且v与x有祖宗关系
2.  后向边: low_x= min(low_x,low_v) v 的祖先一定是 x 的祖先
3.  横叉边:此时分两种情况考虑的
            当 v 点已经退栈时,那么点v可到达的DFS序最小的祖先不是x的祖先,对 low_x 没有贡献; 当点v还在栈中时,v 点可到达的DFS序最小的祖先是x的祖先,有 low_x=min(low_x,low_v) (点v可到达的DFS序最小的祖先一定是x的,v 点能到达的点,x一定能到达)  特别地,由于前向边的更新对于求强连分量没有帮(更新是重复的),所以我们也可以有 low_x=min(low_x,low_v)

那么我们只需判断点 x 连出的边是哪一条就可以转移了。显然,当 dfn_v=0 时(此时v未被访问过),这是一条树枝边。我们再维护一个 col 数组, col_i 表示点 i 所在的强连通分量,在点 i 退栈时,我们对col进行赋值,那么当 dfn_v≠0&&col_v=0 时,点v一定在栈中(后向边指向的点一定在栈中,横叉边指向的点满足此条件时在栈中,而前向边是否存在与答案无关),此时用 low_x=min(low_x,low_v) 转移即可,否则无需转移。该算法时间复杂度为(n+m),因为深度优先遍历每个点只会经过一次,每条边也只会访问一次,而每个点都只会进/出栈一次,所以总时间复杂度为(n+m)

//把一个点当成根提溜出来,抖搂抖搂成一棵树
void dfs(int u)
{
//记录dfs序
//可通过任意多dfs边与最多一条非树返祖边到达的、本强连通分量内最小点
dfn[u]=low[u]=++dfs_clock;
s.push(u);
for(int v:g[u])
{
if(!dfn[v])//树边
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(!sccnum[v])//返祖
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
scccnt++;//强连通块+1
while(1)
{
int x=s.top();
s.pop();
sccnum[x]=scccnt;
sccsz[scccnt]++;
if(x==u) break;
}
}
}

最新文章

  1. jQuery-1.9.1源码分析系列(十) 事件系统——事件绑定
  2. Java-坦克大战
  3. Spring 在web 容器中的启动过程
  4. LR测试https协议设置方法
  5. ***总结:在linux下连接redis并进行命令行操作(设置redis密码)
  6. shell变量自增的几种方式
  7. Python自动化之Django的CSRF
  8. android——屏幕适配大全(转载)
  9. easyui form提交文件(上传图片和文件)
  10. videojs双击全屏幕观看,videojs动态加载视频
  11. .NET Core整理之配置EFCore
  12. Filter简易实现.
  13. Golang入门教程(四)变量声明
  14. whistle工具全程入门
  15. 使用阿里云公网ip建立bind,监听客户端连接失败
  16. GraphQL入门1
  17. Linux(centos)新建,删除,移动,重命名文件夹和文件的命令
  18. 标准库头文件 (CA2T)
  19. shiro 没有权限异常处理
  20. UML uml基础知识

热门文章

  1. Jenkins_创建任务以及定时启动(2)
  2. idea 更换 maven ,并更换阿里镜像
  3. 总结关于spring security 使用 JWT 和 账户密码登录 整合在一起的新感悟
  4. 浅讲EF高级用法之自定义函数
  5. POJ 1664 放苹果 (递推思想)
  6. FastDFS文件的上传和下载
  7. 数组内sizeof与strlen的区别
  8. 【记录一个问题】android ndk下设置线程的亲缘性,总有两个核无法设置成功
  9. 推荐召回--基于物品的协同过滤:ItemCF
  10. django之定义统一返回数据格式与GET/POST装饰器