割点:如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconnected),简称双连通或重连通。一个图有割点,当且仅当这个图的点连通度为1,则割点集合的唯一元素被称为割点(cut point),又叫关节点(articulation point)。
一个顶点u是割点,当且仅当满足(1)或(2) (1) u为树根,且u有多于一个子树。 (2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)。
也可以论述成u有子节点满足dfs(u) <= low(v)且u不为只有一个孩子的根结点。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
const int maxn = 101;
vector <int> G[maxn];
int dfn[maxn], low[maxn];
int dfs_clock;
int cnt;
void dfs(int u, int f)
{
int child = 0;
int flag = 0;
dfn[u] = low[u] = ++dfs_clock;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!dfn[v])
{
dfs(v, u);
child++;
low[u] = min(low[v], low[u]);
if(low[v] >= dfn[u]) flag = 1;
}
else
low[u] = min(low[u], dfn[v]);
}
if(f == 0 && child == 1) flag = 0;
if(flag)cnt ++;
}
int main()
{
int n;
while(scanf("%d", &n) && n)
{
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
dfs_clock = 0;
for(int i = 1; i <= n; i++)
G[i].clear();
getchar();
int h, t;
while(scanf("%d", &h) && h)
{
while(getchar() != '\n')
{
scanf("%d", &t);
G[h].push_back(t);
G[t].push_back(h);
}
}
cnt = 0;
for(int i = 1; i <= n; i++)
if(!dfn[i])
dfs(i, 0);
printf("%d\n", cnt);
}
return 0;
}