文章目录

  • 强连通分量
  • 利用Tarjan算法求强连通分量
  • 来一道例题练手(USACO08DEC)
  • 图论文章汇总

强连通分量

什么是强连通图?
如果一个有向图中,存在一条回路,所有的结点至少被经过一次,这样的图为强连通图。

什么是强连通分量?
在强连图图的基础上加入一些点和路径,使得当前的图不在强连通,称原来的强连通的部分为强连通分量。

求强连通分量有何作用?
在进行对其它图论问题的求解前,利用强连通分量的知识可以把图中强连通的点缩为一个点,减少接下来其它图论操作的计算。
在某些特定的环境下,求强连通分量变相地得出图中的环以及环的长度。

利用Tarjan算法求强连通分量

Tarjan算法的基本思路
首先考虑强连通分量的性质,即存在一条回路能从初始点又回到初始点。在这个查找的过程中,可以对经过的结点标记,当发现某一节点连向的点正好以及被标记过,则说明找到了一条回路,而这个回路上的所有点构成一个强连通分量。为了保存这个强连通分量,我们需要知道这条路上有哪些点,而此时,栈就是一种适合该算法的数据结构。对于每次搜索的点,我们都加入栈中,遇到回路时,在把栈中的元素逐个弹出,记录它们的起始结点,直到栈中弹出的元素正好是起始结点时,结束弹栈,继续搜索其它强连通分量。在这个过程中,所有的点和都有的边都被遍历了一次,所以最终的时间复杂度为O(N+E)O(N+E)O(N+E)

Tarjan算法的实现
为了实现这个过程,Tarjan算法需要装备如下几样东西:
记录搜索顺序的数组dfndfndfn;
记录所属强连通的数组lowlowlow;
表示某结点是否在栈中的数组instackinstackinstack;
一个栈存储搜索路径;
从上面对Tarjan算法的描述中,很容易看出这个算法是基于深度优先搜索实现的。接下来,对Tarjan算法进行逐步推演。
(本人不喜欢使用网上用烂的素材,接下来包括以前的讲解图都是自己手画的,不喜勿喷)





Tarjan算法伪代码

tarjan(u)
{dfn[u]=low[u]=++Index                      stack.push(u)                              for each (u, v) in E                       if (v is not visted)              tarjan(v)                  low[u] = min(low[u], low[v])else if (v in S)                   low[u] = min(low[u], dfn[v])if (dfn[u] == low[u])                     repeatv = stack.pop                print vuntil (u== v)
}

Tarjan算法C++代码模板

#include<iostream>
#include<stack>
#include<vector>
using namespace std;int n,m,cnt,cntb;
vector<int> edge[101];
vector<int> belong[101];
bool instack[101];
int dfn[101];
int low[101];
stack<int> s;void Tarjan(int u)
{++cnt;dfn[u]=low[u]=cnt;s.push(u);instack[u]=true; for(int i=0;i<edge[u].size();++i){int v=edge[u][i];if(!dfn[v]){Tarjan(v);low[u]=min(low[u],low[v]);}else if(instack[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){++cntb;int node;do{node=s.top();s.pop();instack[node]=false;belong[cntb].push_back(node);}while(node!=u);}
}
int main()
{cin>>n>>m;for(int i=1;i<=m;++i){int u,v;cin>>u>>v;edge[u].push_back(v);}Tarjan(1);cout<<"id  :";for(int i=1;i<=n;++i)cout<<i<<" ";cout<<endl;cout<<"dfn :";for(int i=1;i<=n;++i)cout<<dfn[i]<<" ";cout<<endl;cout<<"low :";for(int i=1;i<+n;++i)cout<<low[i]<<" ";cout<<endl;for(int i=1;i<=cntb;++i) {cout<<"SCG "<<i<<" : ";for(int j=0;j<belong[i].size();++j)cout<<belong[i][j]<<" ";cout<<endl;}return 0;
}

按照先前的推演图,生成测试样例

7 11
1 2
2 3
2 5
2 4
3 5
3 7
7 5
5 6
6 7
4 1
4 5

运行结果与推演时一致

来一道例题练手(USACO08DEC)

——题目描述——
每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节。

由于牛棚不太大,FJ通过指定奶牛必须遵循的穿越路线来确保奶牛的乐趣。为了实现这个让奶牛在牛棚里来回穿梭的方案,FJ在第i号隔间上张贴了一个“下一个隔间”Next_i(1<=Next_i<=N),告诉奶牛要去的下一个隔间;这样,为了收集它们的糖果,奶牛就会在牛棚里来回穿梭了。

FJ命令奶牛i应该从i号隔间开始收集糖果。如果一只奶牛回到某一个她已经去过的隔间,她就会停止收集糖果。

在被迫停止收集糖果之前,计算一下每头奶牛要前往的隔间数(包含起点)。

——输入格式——
第1行 整数n。

第2行到n+1行 每行包含一个整数 next_i 。

——输出格式——
n行,第i行包含一个整数,表示第i只奶牛要前往的隔间数。

——输入样例——
4
1
3
2
3

——输出样例——
1
2
2
3

——题解——
本题的数据量还是蛮大的,有1e51e51e5个结点,我们当然不可能对每一个结点进行深度优先搜索。幸运的是,每一个点都只有一条出边,也即意味着,本题中至少有一个环(包括自环),而且,环上的点永远无法走出这个环,环上点的答案就是这个环的长度。而对于不在环上的点,用dfs直到找到一个环,其答案也即环的长度加上搜索到环的步数。环长度的计算,可以利用tarjan算法的思路,用dfn减去low。因地制宜,我写了一个简易版的tarjan.

——Code——

#include<iostream>
#include<stack>
#include<algorithm>
using namespace std;int edge[100005];
int dfn[100005];
bool vis[100005];
int ans[100005];
stack<int> sta;
int n;
int cnt_dfn;
void dfs(int u)
{++cnt_dfn;dfn[u]=cnt_dfn;vis[u]=true;sta.push(u);if(vis[edge[u]]){if(!ans[edge[u]]){int val=dfn[u]-dfn[edge[u]]+1;int v;do{v=sta.top();ans[v]=val;sta.pop();}while(v!=edge[u]);while(!sta.empty()){++val;ans[sta.top()]=val;sta.pop();}}else{int val=ans[edge[u]];while(!sta.empty()){++val;ans[sta.top()]=val;sta.pop();}}}else dfs(edge[u]);
}
int main()
{cin>>n;for(int i=1;i<=n;++i){cin>>edge[i];if(edge[i]==i){ans[i]=1;vis[i]=true;}}for(int i=1;i<=n;++i)if(!vis[i]){cnt_dfn=0; dfs(i);}for(int i=1;i<=n;++i)cout<<ans[i]<<endl;return 0;
}

图论文章汇总

图论简笔(上)——DFS、BFS、Toplogical Sort
图论简笔(下)——最小生成树、最短路径问题
图论——强连通分量(Tarjan算法)
图论——最大流的增广路相关算法(基于Ford–Fulkerson方法的DFS和BFS、Dinic算法)
图论——涵盖Bellman-Ford和Dijkstra的Johnson算法(多源最短路径问题)
图论——最大团问题和最大独立集、二分图相关

图论——强连通分量(Tarjan算法)相关推荐

  1. 强连通分量(Tarjan算法)和缩点

    强连通分量(Tarjan算法)和缩点 一些定义 给定一张有向图,对于图中任意两个节点 xxx 和 yyy ,存在从 xxx 到 yyy 的路径,也存在从 yyy 到 xxx 的路径,则称该有向图为强连 ...

  2. 强连通分量(Tarjan算法) 图解

    强连通分量(Tarjan算法) 前言 第一件事:没事不要while(m–),会带来不幸 第二件事:看博客先看看评论,如果博主他写错了的话- 简介 先讲几个定义 强连通:两个顶点 uuu,vvv 可以相 ...

  3. 有向图强连通分量tarjan算法

    转自:http://www.byvoid.com/blog/scc-tarjan/ http://blog.csdn.net/geniusluzh/article/details/6601514 在有 ...

  4. 强连通分量——tarjan算法缩点

    一. 什么是强连通分量? 强连通分量:在有向图G中,如果两个顶点u,v间(u->v)有一条从u到v的有向路径,同时还有一条从v到u的有向路径,则称两个顶点强连通(strongly connect ...

  5. 有向图的强连通分量--Tarjan算法---代码分析

    本文就是做个代码分析,顺便说下理解. 一.预备知识: 需要知道什么是: 回边.前向边.交叉边 二.上代码: #include<algorithm> #define NIL -1using ...

  6. 图之强连通、强连通图、强连通分量 Tarjan算法

    一.解释 在有向图G中,如果两个顶点间至少存在一条互相可达路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强 ...

  7. 求无向图的连通分量或有向图的强连通分量—tarjan()ccf高速公路

    概念定义: 在图论中,连通图基于连通的概念. 1. 连通(无向图): 若顶点Vi能通过路径到达Vj,那么称为Vi和Vj是连通的 对无向图:若从顶点Vi到顶点Vj有路径相连(当然从j到i也一定有路径), ...

  8. 算法学习:强连通分量 --tarjan

    [定义] [强连通分量] 在一个子图中,任意点能够直接或者间接到达这个子图中的任意点,这个子图被称为强连通分量 [解决问题] 求图的强连通分量 同时能够起到 ...................缩点 ...

  9. HDU2767(强连通分量+Kosaraju算法)

    题意:需要加多少边才能把一个图变成强连通分量 强连通图:在有向图中,任意节点除法都可以到达其余所有节点,则称为强连通图. 强连通分量:在非强连通图的有向图中,选取部分点为强连通图,该强连通子图称为强连 ...

最新文章

  1. Scrum Master角色可能消失吗?
  2. Mac下使用Homebrew 安装MySQL
  3. ServiceStack 项目实例 001 建立项目结构
  4. iOS 查询数组中的对象
  5. CWNA考试常见RF术语
  6. akka---Getting Started Tutorial (Java): First Chapter
  7. 阿里云服务器购买后的配置指南
  8. EAT/IAT Hook
  9. 2.4g和5g要不要合并_请问千兆路由器,2.4g与5g是双频合一还是分开,该选择哪个?...
  10. 动态切换数据源(spring+hibernate)
  11. 入门机器学习(十一)--机器学习系统的设计
  12. OpenGL——颜色混合 glBlendFunc函数
  13. sse java8_Java SSE 服务器推送WEB页面接收数据
  14. 分享294个PHP博客系统,总有一款适合你
  15. 虚拟机Ubuntut tftp服务不启动,service tftpd-hpa restart 失败的处理
  16. 平均销售额计算机公式,销售额是什么意思(销售额的基本计算公式)
  17. 埃默里大学计算机科学排名,埃默里大学CS专业研究生排名,来试试你弄懂多少...
  18. 微信小程序 基础 - 19 (登录后用户头像的更新)
  19. 阿里云服务器,解析二级域名
  20. c语言实现五子棋人人对战教程

热门文章

  1. 按什么键启用计算机管理,电脑结束任务按什么键
  2. 趣味程序设计_抢n游戏(总结规律)
  3. 关于联想投票 华为3GPP参会代表发文:上纲上线指责联想很荒唐
  4. 股票估值模型基础-股票内在价值的计算方法
  5. 数字几何之笛卡儿的法国良心存在时间谭
  6. 关于CSDN blog博客被封的说明
  7. 天涯文章下载工具TianyaCrawl
  8. 计算机控制 根轨迹,根轨迹方法的控制器设计
  9. 计算机用户怎么配置漫游,AD用户设置配置漫游配置文件到服务器
  10. VOS错误代码分机及解决方案