割点的定义:
在一个无向图中,去掉某一个点,该无向图不再连通,这样的点称为割点
求点割集的方法:利用tarjan算法的思想,用数组dfn[v]存储DFS遍历到点v的时间,数组low[v]存储点v能追溯到最早的祖先节点。
- 判断一点是否是割点:
1.如果这个点是根节点并且这割点有不少于两个儿子则该节点一定是割点(去掉根节点的树其他的分支一定不再连通) 如果这个点v不是根节点,但是这个点存在一个儿子low[i]>=dfn[v];(说明要到i必须经过v)则v一定是一个割点
实现算法
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int V = 110 ;
vector<int>mp[V];//储存图
int low[V],dfn[V],numlock[V];
int sum,numson,deep;
int vis[V];
void init()
{
memset(dfn, 0, sizeof(dfn));
memset(vis, 0, sizeof(vis));
memset(numlock, 0, sizeof(numlock));
memset(low, 0, sizeof(low));
memset(mp, 0, sizeof(mp));
numson = sum = deep = 0;
}
void dfs(int x){
deep ++;//递归的深度
low[x] = dfn[x] = deep;
vis[x] = 1;//表示已经访问过
for(int i=0;i<mp[x].size();i++){
int y = mp[x][i];
if(!vis[y]){
dfs(y);
low[x] = min(low[x], low[y]);//得到最早的祖先
if(low[y]>=dfn[x]&&x!=1)numlock[x]++;
else if(x==1)numson++;//这点是根节点,儿子数+1
}
else low[x] = min(low[x], dfn[y]);//已经访问过,说明已经在栈中,有圈的形成,更新low[x]取最小值
}
}
int main()
{
int n;
while(scanf("%d",&n)&&n){
init();
int x,y;
while (scanf("%d",&x)&&x) {
while(getchar()!='\n'){
scanf("%d",&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
}
dfs(1);
for(int i=1;i<=n;i++)
if(numlock[i])sum++;
if(numson>1)sum++;
printf("%d\n",sum);
}
return 0;
}