//两种方法求割点个数....
//Findcut里是否为根节点刚开始直接忽略了....
导致找了好久的bug....看了别人的博文才知道还要判断是否为根结点.......好歹解决了...
还有就是vis标记和Dfn的问题...得在刚开始就标记或赋值...不然WA
#include<iostream>
#include <vector>
#include <string.h>
#include <algorithm>
using namespace std;
const int nMax = 1000+10;
bool cut[nMax];
int Dfn[nMax], low[nMax], parent[nMax];
int vis[nMax];
int root;
vector<int> adj[nMax], CutEdge[nMax];
void addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
}
void Tarjan(int u, int pa, int indx) {
// parent[u] = pa;
Dfn[u] = low[u] = indx;
for(int i = 0; i < adj[u].size(); ++i) {
int v = adj[u][i];
if(Dfn[v]==0) {
parent[v] = u;
Tarjan(v, u, indx+1);
low[u] = min(low[u], low[v]);
} else if(pa != v)
low[u] = min(low[u], Dfn[v]);
}
}
void findcut(int dep, int u) {
Dfn[u] = low[u] = dep;
vis[u] = true;
int sum = 0;
for (int i=0; i<adj[u].size(); i++) {
int v = adj[u][i];
//if (!dfn[v])
if(!vis[v]) {
parent[v] = u;
sum ++;
findcut(dep+1, v);
low[u] = min(low[u], low[v]);//确保low[u]最小
if (low[v] >= Dfn[u] && u != root) {//不是根结点
if(parent[u] != v)
cut[u] = true, CutEdge[u].push_back(v);//割边
}
if(u == root && sum >= 2) cut[u] = true;//根结点至少有两个孩子
} else if(parent[u] != v && Dfn[v] < low[u]) { //v的父节点不能用来跟新他的low值
low[u] = min(low[u], Dfn[v]);//回溯继续
}
}
}
void init() {
for(int i=0; i<nMax; i++) {
adj[i].clear();
CutEdge[i].clear();
}
memset(vis, false, sizeof(vis));
memset(cut, false, sizeof(cut));
memset(Dfn, 0, sizeof(Dfn));
memset(low, 0, sizeof(low));
memset(parent, 0, sizeof(parent));
}
int main() {
//初始化
int u, v, n, m;
while (cin >> n && n) {
init();
while(cin >> u && u)
while(getchar() != '\n') {
cin >> v;
addEdge(u, v);
}
//建好图后调用
for(int i=1; i<=n; i++)
root = i, findcut(1, i); //以i为根节点,可以在下次选另一点为根节点时,判断上次的根结点 是否为割点
//输出割点个数
// Tarjan(1, 0, 1);
int cnt = 0;
//方法二
/* int rootcnt = 0;//判断割点
for(int i=2; i<=n; i++) {
int u = parent[i];
if(u == 1) rootcnt++;
else if(low[i] >= Dfn[u])
cut[u] = true;
}
if(rootcnt > 1) cut[1] = true;
*/
for(int i=1; i<=n; i++) {
if(cut[i])
cnt++;
}
cout<< cnt << endl;
}
return 0;
}