图论-有向图缩点

强连通(strongly connected): 在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。

强连通图: 如果 在一个有向图G中,每两个点都强连通,我们就叫这个图,强连通图。

强连通分量strongly connected components):在一个有向图G中,有一个子图,这个子图每2个点都满足强连通,我们就叫这个子图叫做 强连通分量 。

有向图的缩点就是把有向图中强连通分量缩成一个点(道理很简单,我到了这个强连通分量的任何一点,那么这个强连通分量就能被我访问了),在处理有向图的连通性问题时有很多作用。

比如如下问题:

给出一个 0 ≤ N ≤ 105 点数、0 ≤ M ≤ 105 边数的有向图,

输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合,输出这些集合升序排序后字典序最小的。

第一行为两个整数 1 ≤ n, m ≤ 105
接下来 M 行,每行两个整数 1 ≤ u, v ≤ 105 表示从点 u 至点 v 有一条有向边。

数据保证没有重边、自环。

第一行输出一个整数 z,表示作为答案的点集的大小;

第二行输出 z 个整数,升序排序,表示作为答案的点集。

7 10
4 5
5 1
2 5
6 5
7 2
4 2
1 2
5 3
3 5
3 6
2
4 7

不明白缩点的话,是很难做出来的,也有其他方法,这里这是举个例子来解决问题。

缩点其实难在求有向图的强连通分量上面,这个得先去了解一下点击打开链接

我们把输出的代码改一下,记录到一个数组里面并且同时给每一个点打上标记,即这些点都是一个强连通分量里面的

图论-有向图缩点_第1张图片num记录的是强连通分量数量,p是记录第几个强连通分量里面的点,unicom表示每一个点属于第几个强连通分量。

算法复杂度O(N+E)

这样我们的预备工作就做好了。把N个点划分成了num个强连通分量块了。

问了验证有向图的联通性,我们还需要利用边的信息。

假如存a->b的边而且unicom[a]!=unicom[b]即它们俩个点不属于同一强连通分量。那么也就是说我们到达了点a,那么包括点b的强连通分量就全部可以到达了。

我们给强连通分量unicom[b]打上标记,这块不用考虑了,考虑a就行了。

S数组保存起点 E数组保存终点  e表示边的条数。

算法复杂度O(E)

总时间复杂度O(E+N)

基本上这个连通性的问题就解决了,对于那些没有打上标记的强连通分量就需要选取到达了。

代码如下:

#include
using namespace std;

const int maxn=1e5+100;
vector G[maxn],p[maxn],ans;
int low[maxn],dfn[maxn],Stack[maxn],S[maxn],E[maxn],n,e,cnt,Index,num;
int link[maxn],unicom[maxn];
bool vis[maxn];

void tarjan(int u)
{
    low[u]=dfn[u]=++cnt;
    vis[u]=true;
    Stack[++Index]=u;
    for (int i=0;i









你可能感兴趣的:(图论)