题意:
一个无向图,求其中割点的个数目。
输入数据
第一行一个 n 代表有 n 个点
接下来有多行,一直到读入一个 0,算整个地图的读入结束,再读入一个0,文件数据结束。
每行有第一个数字a,代表接下来的数字都和 a 相连。
割点:无向连通图中,如果删除某点后,图变成不连通了,则称该点为割点。
这里割点和 桥 都是无向图里的概念,大家在这里不要混淆了。
求割点
一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。(也就是说 v 没办法绕过 u 点到达比 u dfn要小的点)
注:这里所说的树是指,DFS下的搜索树。
参考资料:http://www.cnblogs.com/en-heng/p/4002658.html
http://blog.csdn.net/guard_mine/article/details/43021981
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
struct node
{
int next;
int to;
}edge[N * N];
bool instack[N];
bool cut[N];
int head[N];
int DFN[N];
int low[N];
int cnt, tot, ord, root;
void addedge (int from, int to)
{
edge[tot].to = to;
edge[tot].next = head[from];
head[from] = tot++;
}
void tarjan (int u, int fa)
{
DFN[u] = low[u] = ++ord;
instack[u] = 1;
int cnt = 0;
for (int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].to;
if (v == fa)
{
continue;
}
if (DFN[v] == -1)
{
tarjan(v, u);
cnt++;
if (low[u] > low[v])
{
low[u] = low[v];
}
if (root == u && cnt > 1)
{
cut[u] = 1;
}
else if (u != root && low[v] >= DFN[u])
{
cut[u] = 1;
}
}
else if (instack[v])
{
low[u] = min(low[u], DFN[v]);
}
}
}
void init ()
{
memset (DFN, -1, sizeof(DFN));
memset (low, 0, sizeof(low));
memset (instack, 0, sizeof(instack));
memset (cut, 0, sizeof(cut));
memset (head, -1, sizeof(head));
tot = 0;
ord = 0;
}
void solve (int n)
{
root = 1;
tarjan (1, -1);
int ans = 0;
for (int i = 1; i <= n; ++i)
{
if (cut[i])
{
ans++;
}
}
printf("%d\n", ans);
}
int main()
{
int n;
int u, v;
while (~scanf("%d", &n), n)
{
init();
while (scanf("%d", &u), u)
{
while (getchar() != '\n')
{
scanf("%d", &v);
addedge (u, v);
addedge (v, u);
}
}
solve(n);
}
return 0;
}