概念定义:

在图论中,连通图基于连通的概念。

1. 连通(无向图):
若顶点Vi能通过路径到达Vj,那么称为Vi和Vj是连通的

对无向图:若从顶点Vi到顶点Vj有路径相连(当然从j到i也一定有路径),则称i和j是连通的。

2.强连通和弱连通(有向图)
若顶点Vi和Vj能通过路径单向到达,那么称为Vi和Vj是弱连通的。
若顶点Vi和Vj能通过路径相互到达,那么称为Vi和Vj是强连通的。

3.连通图和强连通图
如果图中任意两点都是连通的,那么图被称作连通图。
如果此图是有向图,任意两点强连通,则称为强连通图 (注意:需要双向都有路径)

3.连通分量和强连通分量
无向图 G(V,E)中:一个极大连通子图称为 G的一个连通分量(或连通分支)连通图只有一个连通分量,即其自身;非连通的无向图有多个连通分量。

有向图 G=(V,E) 中:一个极大强连通子图称为 G的一个强连通分量。若对于V中任意两个不同的顶点 x和 y,都存在从x到 y以及从 y到 x的路径,则称 G是强连通图。强连通图只有一个强连通分量,即是其自身;非强连通的有向图有多个强连分量。

无向图中,要求得最大连通子图,十分简单,用DSF历遍每一个点,外部再套一层循环即可。但是对于有向图,DFS不能直接求最大连通子图,因为两个节点之间并不是双向联通的,从a->b,不一定可以从b->a,这个时候我们介绍一种新的算法,tarjan

判断一幅图是否连通或强连通

无向图:
对于无向图,只要所有节点可以相互连接即可,用DFS历遍一次,再判断所有的点是否都被访问即可判断复杂度是O(V)

void dfs(int U)
{visit[s]=1;for(int i=0;i<G[u].size();i++)//访问子节点{int v=G[u][v].id;//取出子节点if(!visit[v]) dfs(v);}
}
bool travel()
{for(int i=1;i<=n;i++){if(!visit) return 0;//不能一次性遍历,说明不连通}return 1;//全部访问
}

有向图:
这里有两种方法:
(1)用DFS历遍外层再套一层循环,对每一个点DFS历遍,每次历遍完判断是否有未访问到的,未访问则不强连通,复杂度是O(V^2)

void dfs(int U)
{visit[s]=1;for(int i=0;i<G[u].size();i++)//访问子节点{int v=G[u][v].id;//取出子节点if(!visit[v]) dfs(v);}
}
bool travel2()//判断有向图是否强连通
{for(int j=1;j<=n;j++){dfs(j);for(int i=1;i<=n;i++){if(!visit) return 0;//不能一次性遍历,说明不连通}fill(visit,visit+maxn,0);}return 1;//全部访问
}

(2)tarjan()算法求强连通分量,如果该图只存在一个强连通分量,那么该图强连通

void tarjan(int s)
{st.push(s);//入栈visit[s]=1;//标记入栈dfn[s]=low[s]=index++;//标记时间for(int i=0;i<G[s].size();i++){int v=G[s][i];//取出子节点if(!dfn[v])//子节点未访问{tarjan(v);low[s]=min(low[s],low[v]);}else if(visit[v])//访问过且已经在栈中{low[s]=min(low[s],dfn[v]);}}if(low[s]==dfn[s])//这是最大连通子图的根节点{int num=0;int u;do{u=st.top();//取出首元素num++;st.pop();//弹出visit[u]=0;//同时标记出栈}while(s!=u);ans+=num*(num-1)/2;//C(n,2)个连通点}
}
for(int i=1;i<=n;i++){if(!dfn[i]) tarjan(i);//当未访问过某个节点是tarja(i)}cout<<ans<<endl;

求一幅图的连通分量或强连通分量

(1)无向图也很简单,DFS历遍一次,外部套一层循环,对未访问的节点继续DFS:

void DFS(int u)//dfs历遍判断无向图是否连通
{visit[u]=1;cout<<u<<' ';for(int i=0;i<G[u].size();i++)//访问子节点{int v=G[u][v];//取出子节点if(!visit[v]) dfs(v);}
}
bool travel3()//求有向图的连通分量
{for(int i=1;i<=n;i++){if(!visit[i]) {cout<<endl;DFS(i);//不能一次性遍历,说明不连通,继续DFS}}
}

(2)求有向图的强连通分量tarjan()

首先我们考虑为什么一个图会强连通,这是因为图中含有环,因为有环一个点到达另一个点而另一个点沿着环回路回到这个点。那么我们如何利用这个特点去求最大连通子图呢?
1. 设想如果我们给每一个节点按照访问顺序标记,当沿着某条路访问时一个节点的子节点又出现在这条路中,那么不就形成了一个环吗!!
2. 我们可以给这个最大连通子图标号,设根节点的序号最小,当一个节点的子节点又出现在这条路中我们把这个子节点的标号重置为根节点的编号(最小编号),然后由子节点返回自身的标号,父节点接收到这个标号也重置为当中较小的编号,那么整条回路的标号不就都重置为根节点的标号了吗!!
这样我们可以得到一个连通图,下面是细节:

  1. 对每一个节点有两层标号,一个是dfn[s],表示标记的时间,一个是low[s]表示根节点的时间序号
  2. 用栈来存储最大连通子图
  3. 每次访问一个节点,标记时间dfn[s]=low[s]=index++,入栈,然后访问子节点,如果子节点没有访问过,则tarjan()访问之,并将s点的low[s]重置为min(low[s],low[v]),如果访问过而且在栈中,那么说明找到了环,重置low[s]=min(low[s],low[v]);
  4. 当if(low[s]==dfn[s])//这是最大连通子图的根节点,弹出s以及s之后所有的节点,表示最大连通子图
    这样算法的时间代价是O(V+E)
tarjan()
void tarjan(int s)
{st.push(s);//入栈dfn[s]=low[s]=index++;//标记时间for(访问子节点){if(子节点未访问){tarjan(v);low[s]=min(low[s],low[v]);}else if(访问过且已经在栈中)//存在环{low[s]=min(low[s],low[v]);}}if(low[s]==dfn[s])//最大连通子图的根节点{弹栈,弹出s以及s之后所有的节点,表示最大连通子图;}
}

下面是CCF高速公路题的解法

#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int maxn=1010;
vector<int>G[maxn];
stack<int>st;
int dfn[maxn]={0},low[maxn]={0},visit[maxn]={0};
int time=1;//访问时间
int n,m;//节点数以及边数
void tarjan(int s)
{st.push(s);//入栈dfn[s]=low[s]=time++;//新进点的初始化visit[s]=1;//s在栈里for(int i=0;i<G[s].size();i++){int v=G[s][i];//取出子节点if(!dfn[v])//未被标记访问过{tarjan(v);low[s]=min(low[s],low[v]);}else if(visit[v])//已经访问并且已经在栈里面//说明成环{low[s]=min(low[s],low[v]);//比较访问的先后得出子父关系就是连接对应关系}}if(low[s]==dfn[s]) //是强连通分量的根节点{int u;do{u=st.top();printf("%d ",u);visit[u]=0;//出栈st.pop();//弹出}while(u!=s);printf("\n");}
}
int main()
{scanf("%d %d",&n,&m);//输入int u,v;for(int i=0;i<m;i++){scanf("%d%d",&u,&v);G[u].push_back(v);//构图}for(int i=1;i<=n;i++){if(!dfn[i]) tarjan(i);}return 0;
}
/*
6 8
1 2
1 4
2 3
2 5
3 6
4 5
5 1
5 6
*/

求无向图的连通分量或有向图的强连通分量—tarjan()ccf高速公路相关推荐

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

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

  2. 有向图的强连通分量——Tarjan

    在同一个DFS树中分离不同的强连通分量SCC; 考虑一个强连通分量C,设第一个被发现的点是 x,希望在 x 访问完时立刻输出 C,这样就可以实现 在同一个DFS树中分离不同的强连通分量了. 问题就转换 ...

  3. Tarjan 求有向图的强连通分量

    Tarjan 算法与有向图的连通性 Tarjan 算法是基于对图进行深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个栈,回溯时可以判断栈顶到栈中的节点 ...

  4. 使用并查集实现查找无向图的连通分量和求解有向图的强连通分量

    目录 1.无向图的连通分量 2.求解连通分量算法的实现 3.有向图的强连通分量 4.求解有向图的强连通分量 使用C语言实现并查集 有向图和无向图 1.无向图的连通分量 无向图G中,如果存在从顶点v1到 ...

  5. 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...

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

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

  7. 有向图的强连通分量,割点与桥

    有向图的强连通分量 1.Tarjan /* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #includ ...

  8. 缩点(有向图的强连通分量)学习笔记

    缩点(有向图的强连通分量)学习笔记 1.什么是强连通分量?: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路 ...

  9. 有向图的强连通分量(SCC)

    有向图的强连通分量(SCC) 1. 有向图的强连通分量原理 原理 强连通分量是针对有向图来说的.如下的讲解默认都是针对有向图的. 连通分量:对于一个有向图中的一些点来说,如果任意两点都能相互到达,则称 ...

最新文章

  1. 动态规划 RQNOJ 吃西瓜 最大子段和三维版
  2. 安装pyqt和pycharm配置
  3. NCNE二级复习资料-网络监视、管理和排错
  4. 【顶尖技术人是怎样炼成的】清华博士的模型信仰——对话阿里云 MVP陈旸
  5. 获国际架构顶会ATC2021最佳论文!Fuxi2.0去中心化的调度架构详解
  6. 用python写一个自动注册脚本_python实现自动化上线脚本的示例
  7. 弱网络环境下最优调度和优化传输层协议方案
  8. 表格 滚动条 (tbody部分滚动)
  9. hashmap7源码浅析及与hashmap8的比较
  10. 126 MySQL存储引擎概述
  11. docker 重启gitlab_gitlab从入门到绝望
  12. linux内核源码各个目录
  13. java扫描免费代理服务器
  14. 【OpneWRT】编译ipk
  15. 测试工具学习——JMeter
  16. Kibana:为 Dashboard 创建链接 drilldown - 7.11 版本
  17. 苹果12系列手机均支持5G
  18. php phalcon 安装,安装phalcon 开发工具
  19. 示例代码-协方差,黎曼协方差计算.
  20. 【自】2014会计准则科目和主要账务处理对照

热门文章

  1. DirectX 11 编程指南
  2. 打印机共享后每天要重新连接
  3. centos7 搭建深度学习环境
  4. 编写Java程序,使用Swing事件处理机制实现用户登录和英雄信息显示
  5. 一个网站从0到1搭建部署上线的完整流程(包教包会)
  6. mysql MYSQL远程访问 授权IP
  7. 大疆创始人汪滔的创业路
  8. 中国社会追踪调查数据CGSS区县码
  9. 【编程】工具 - Compuware 全套产品的许可文件(License.xml)
  10. Django面试题和出现的一些问题