下面是我刚转专业到计算机专业的时候学的图,现在看看当时的我真傻逼。
其实判断是否为割点只需要看删除该点后整个图还是不是联通图,一共分为两步
①、删除指定的点,(在邻接矩阵中该点的行和列全部置0就好了,推荐使用 fill() )
②、DFS遍历图看看有几个联通分量。
下面的不要看了,我不删了它只是留个纪念
割点什么是割点呢;就是在一个连通图中删除一个点就导致整个图不连通了,那么这个点就叫做割点;DFS搜索树,我们可以发现有两类节点可以成为割点:
1、对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
2、对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。
我们用dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小),这里的dfn low 跟上面的功能是一样的。,那么low[u]的计算过程如下:
#include<bits/stdc++.h>
#define VertexNum 1000
#define MinNum 0
using namespace std;
int n,m,Graph[VertexNum][VertexNum]; //n表示图对应有n个节点,m表示有m条边
int num[VertexNum],low[VertexNum],flag[VertexNum]={0},index=0;
int x,y;//表示输入的边的邻接点
int X,Y;
int dfs(int cur,int fat)
{
int child=0; //用来记录当前节点的子节点个数
index++;
num[cur] = index; //表示当前(cur)节点的dfs访问顺序是第index
low[cur] = index; //当前顶点能够访问到的最早的顺序序号,一开始就是自身。
for(int i=1;i<=n;i++) //开始循环遍历其他节点
{
if(Graph[cur][i]==1) //与cur存在连接的节点进入判断语句。
{
if(num[i]==0) //没有被访问的节点
{
child++; //孩子数加一,多个循环,child 数就表示cur的子森林数
dfs(i,cur); //继续进一步dfs
low[cur] = low[cur]>low[i]?low[i]:low[cur];
if(cur!=1 && low[i]>=num[cur]) //low[i]>=num[cur]的含义:以节点v为根的子树所能追溯到最早的祖先节点要么为i要么为cur。
flag[cur] = 1; //将cur标记为断点
if(cur==1&&child>=2) //若根有两个子森林
flag[cur] = 1; //将cur标记为断点
}
else if(i!=fat) //若遍历的i点不是自己父节点,这样就可能与父节点的父节点存在连接
{
low[cur] = low[cur]>num[i]?num[i]:low[cur];
}
}
}
return 0;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
Graph[i][j]=MinNum;//进行初始化,将各条边的距离初始化为“无穷”
}
for(int i=1;i<=m;i++){ //输入m条边的信息
if(i<=m)
{
cin>>x>>y;
Graph[x][y]=1;
Graph[y][x]=1;
}
}
dfs(1,1);
int count;
for(int i=1;i<=n;i++){
if(flag[i]==1)
count++;
}
cout<<count;
return 0;
}