学习笔记 强联通分量&缩点

发布时间 2023-08-12 22:58:35作者: g1ove

1.概念

强连通:在一个有向图 G 中,若同时存在从点 u 到点 v 和从点 v 到点 u 的有向路径,则称点 u 和点 v 是强连通的。

强连通图:若有向图 G 中任意两点均是强连通的,则称 G 为强连通图。

强连通分量:在有向图 G 中,任意一个极大强连通子图称作强连通分量。
(什么是极大呢?假设一个强连通子图包含的点集为 S,若对于任意一个不在 S 中的点 v,均能在 S 中找到至少一个点 u,使得点 u 和点 v 不是强连通的,则该子图为极大强连通子图,即强连通分量。)


2.怎么求强联通分量

\(Tarjan\)算法

思想:

1.把整个图看成一颗搜索树+存在返祖边
2.每个点是一定能到达的
3.如果有返祖边,那就是强联通分量的一个点
4.只有没有返祖边,且当前的dfn值最大,这就是整个强联通分量最大的点

Code:

#include<bits/stdc++.h>
#define MAXN 10005
#define ll long long
using namespace std;
int n,m,w[MAXN];
int head[MAXN],tot=1;
int q[MAXN],l;
int vis[MAXN],low[MAXN],id[MAXN],col[MAXN],cnt,tc;
struct edge{
	int to,next;
}e[MAXN*10];
void add(int u,int v)
{
	e[tot].to=v;
	e[tot].next=head[u];
	head[u]=tot++;
}
void tarjan(int x)
{
	q[++l]=x;
	vis[x]=1;
	id[x]=low[x]=++cnt;
	for(int i=head[x];i;i=e[i].next)
	{
		int to=e[i].to;
		if(vis[to]==2) continue;
		if(vis[to]==0) tarjan(to);
		low[x]=min(low[x],low[to]);
	}
	if(low[x]==id[x])
	{
		tc++;
		int t;
		do
		{
			t=q[l--];
			col[t]=tc;
			vis[t]=2;
		}while(t!=x);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	for(int i=1;i<=n;i++)	
		if(!id[i]) tarjan(i);

Part2 缩点

在强联通分量中很多可以合并,这样就可以把它们缩成一个点

目的:从有向有环图变成了有向无环图

Code省略