Tarjan算法
dfs树:对图进行dfs时删除所有未经过的边形成的树
dfs序:对点dfs的顺序
对有向图进行dfs时遇到的边:
~树边:一般边,构成树
~返祖边:指向祖先的边
~横叉边:(从一个叉跳向另一个)指向搜索过的点的边
维护dfs的栈,树根到当前点的节点序列
dfn[u]:u的dfs序
low[u]:u通过树边和至多一条返祖边能访问的dfn的最小值
如果一个点能访问到的最早的点为这个点本身(low=dfn)
就会形成一个新的强连通分量!
void dfs(int u){ dfn[u] = low[u] = ++dfs_clock; s.push(u); /*考虑u能到的所有点v*/{ if(!dfn[v]) dfs(v) low[u] = min(low[u],low[v]);//树边 else if(!sccnum[v]) low[u] = min(low[u],dfn[v]);//返祖边 else //横叉边,不管 } if(low[u]==dfn[u]){ //产生了新的scc! scccnt++; //以下遍历了scc所有点,可以在此记录信息 while(1){ int x = s.top();s.pop(); sccnum[x] = scccnt; sccsz[scccnt]++; if(x == u) break; } } }
以下为无向图中概念:
割点:删去这个点,图的联通块个数增加
桥:删去这条边,图的联通块个数增加
点联通度:最小点数使得删去之后图不连通
边联通度:最小边数使得删去之后图不连通
点双:无割点/点联通度>=2/任意2点间存在至少2条点不重复路径
边双:无桥/边联通度>=2/任意2点间存在至少2条边不重复路径
点双边双联通分量:无向图的极大点双/边双联通子图
割点将图分割成若干点双,桥将图分割成若干个边双
桥不属于任何边双,割点属于与其相连的所有点双
对于边(u,v):
若low[v] > dfn[u]则(u,v)是桥;
若low[v] <= dfn[u] 则u是割点(只有一个儿子的根节点除外);
Tarjan:把图上问题转化为树问题求解。
例:
给你一个有向图,标记其中一点,该点所能到达的点也会被标记,
求至少标记点个数;
求至少加入多少单向边可以使手动标记任意一个点就能标记所有点;
分析:Q1:入度为0的点个数
Q2:加入的单向边需满足(i,j)且点i出度为0,点j入度为0
不断加入,直到消除所有入度为0和出度为0的点就好了
注意:操作中要对每一个入度为0的点,加入一个不能到达它的(有出度为0的点?出度为0的点:任意点)
答案:max(入度为0点个数,出度为0点个数
max(入度为0的点个数,出度为0的点个数)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】