题目链接:http://poj.org/problem?id=1144
# include<iostream>
# include<stdio.h>
# include<algorithm>
# include <string.h>
# include <vector>
# include <stack>
# define MAXN 5000
using namespace std;
int dfn[MAXN],low[MAXN];
stack<int >stk;
vector<int > vt[MAXN];
int cut[MAXN];
int ans=0,indx;
int root;
void init()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(cut,0,sizeof(cut));
for(int i=0; i<MAXN; ++i)
vt[i].clear();
root = ans = 0;
indx = 1;
}
void Tarjan(int u)
{
dfn[u] = low[u] = indx++;//访问顺序
for(int i=0; i<vt[u].size(); ++i)
{
int v = vt[u][i];
if(!dfn[v])
{
Tarjan(v);
low[u] = min(low[u],low[v]);
//判断割点
//如果 low[v] >= dfn[u],则以v为起点的点,就不能回到u点的祖先
//即u点是割点
if(low[v] >= dfn[u] && u != 1)
cut[u]++;
else if(u == 1) root++;//u为根,那么孩子节点数加1
}
else
low[u] = min(dfn[v],low[u]);
}
}
int main(void)
{
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
int N;
while(~scanf("%d",&N))
{
if(!N) break;
init();
int k;
while(1)
{
scanf("%d",&k);
if(!k) break;
int t;
while(getchar() != '\n') // 如果是回车,则结束一行的输入
{
scanf("%d",&t);
vt[k].push_back(t);
vt[t].push_back(k);
}
}
Tarjan(1);//默认选1为根
if(root > 1) ans++;//如果根有大于等于两个子树,则根必定为割点
for(int i=1; i<=N; ++i)
if(cut[i]) ans++;
cout << ans <<endl;
}
return 0;
}