题目:6343:点双连通分量 (tzcoder.cn)
相关概念分析
割点: 若无向图G中,存在一个点,当该点被删除时,图G不再联通。
连通分量:互相联通的子图
极大连通子图:连通图只有一个极大连通子图,就是它本身。(是唯一的)非连通图有多个极大连通子图。(非连通图的极大连通子图叫做连通分量,每个分量都是一个连通图)。连通子图中没有割点。
点双连通:在一个无向图中,若任意两点间至少存在两条“点不重复”的路径。
点-双连通分量:一个子图满足点双连通且在图G中是极大联通子图。
描述
给定一个n个点m条边的无向连通图,求该图中“点双连通分量”的个数。
输入
第一行,n, m。
接下来m行,每行两个整数u,v,表示一条无向边(u,v)
对于100%的数据,2<=n,m<=2 * 10^5。
输出
输出点双连通分量的数量。
样例输入:
5 6
1 2
2 3
1 3
3 5
4 5
3 4
样例输出:
2
思路:
发现割点,点双数量加1。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
using namespace std;
int a[N],nxt[N],head[N];
int dfn[N],low[N],sji,k,flag[N],top,num=0;
void add(int x,int y)
{
a[++k]=y;
nxt[k]=head[x];
head[x]=k;
}
void tarjan(int u,int v)
{
dfn[u]=low[u]=++sji;//赋时间值
for(int i=head[u];i!=0;i=nxt[i])
{
int nx=a[i];
if(dfn[nx]==0)
{
tarjan(nx,v);
low[u]=min(low[u],low[nx]);
if (low[nx]>=dfn[u])
{
num++;
}
}
low[u]=min(low[u],dfn[nx]);//更新时间
}
}
int main()
{
int n,m;
k=0;
scanf("%d%d",&n,&m);
memset(flag,0,sizeof(flag));
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for (int i=1;i<=n;i++)
{
if(dfn[i]==0)
{
top=0;
tarjan(i,i);
}
}
printf("%d\n",num);
return 0;
}