学习笔记 强联通分量&缩点
1.概念
强连通:在一个有向图 G 中,若同时存在从点 u 到点 v 和从点 v 到点 u 的有向路径,则称点 u 和点 v 是强连通的。
强连通图:若有向图 G 中任意两点均是强连通的,则称 G 为强连通图。
强连通分量:在有向图 G 中,任意一个极大强连通子图称作强连通分量。
(什么是极大呢?假设一个强连通子图包含的点集为 S,若对于任意一个不在 S 中的点 v,均能在 S 中找到至少一个点 u,使得点 u 和点 v 不是强连通的,则该子图为极大强连通子图,即强连通分量。)
2.怎么求强联通分量
算法
思想:
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省略
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架