题意为求出所给图的割点
割点:一个顶点u是割点,当且仅当满足(1)或(2) :(1) u为树根,且u有多于一个子树。(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得dfn(u)<=Low(v)
#include <set>
#include <cmath>
#include <stack>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 5;
const int maxm = 1e5 + 5;
struct Edge {
int to, nxt;
bool cut; //是否为桥的标记
Edge() {}
Edge(int _to, int _nxt, bool _cut) : to(_to), nxt(_nxt), cut(_cut) {}
} edge[maxm];
int head[maxn], tot;
int low[maxn], dfn[maxn], Stack[maxn];
int Index, top;
bool Instack[maxn];
bool cut[maxn];
int add_block[maxn];
int bridge;
void addedge(int u, int v) {
edge[tot] = Edge(v, head[u], false);
head[u] = tot++;
}
void Tarjan(int u, int pre) {
int v;
low[u] = dfn[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
int son = 0;
for(int i = head[u]; i != -1; i = edge[i].nxt) {
v = edge[i].to;
if(v == pre) continue;
if(!dfn[v]) {
son++;
Tarjan(v, u);
if(low[u] > low[v]) low[u] = low[v];
if(low[v] > dfn[u]) {
bridge++;
edge[i].cut = true;
edge[i ^ 1].cut = true;
}
if(u != pre && low[v] >= dfn[u]) {
cut[u] = true;
add_block[u]++;
}
}
else if(low[u] > dfn[v])
low[u] = dfn[v];
}
if(u == pre && son > 1) cut[u] = true;
if(u == pre) add_block[u] = son - 1;
Instack[u] = false;
top--;
}
void solve(int n) {
memset(dfn, 0, sizeof(dfn));
memset(Instack, false, sizeof(Instack));
memset(add_block, 0, sizeof(add_block));
memset(cut, false, sizeof(cut));
Index = top = 0;
bridge = 0;
for(int i = 1; i <= n; ++i)
if(!dfn[i]) Tarjan(i, i);
int ans = 0;
for(int i = 1; i <= n; ++i)
if(cut[i]) ans++;
printf("%d\n", ans);
}
void init() {
tot = 0;
memset(head, -1, sizeof(head));
}
int g[110][110];
int main()
{
int n;
while(scanf("%d", &n) && n) {
int u, v;
char op;
memset(g, 0, sizeof(g));
while(~scanf("%d", &u) && u) {
while(~scanf("%d%c", &v, &op)) {
g[u][v] = g[v][u] = 1;
if(op == '\n') break;
}
}
init();
for(int i = 1; i <= n; ++i)
for(int j = i + 1; j <= n; ++j)
if(g[i][j]) {
addedge(i, j);
addedge(j, i);
}
solve(n);
}
}