题意:多组数据,每组数据给出一个数n,接下来最多有n行,表示每一行第一个数字与该行的后面几个数字是直接连接的。让你找出每一组数据有几个割点。
注意:1.每次敲回车都跳出循环
2.判断一个点为割点的两个条件
3.用链式向前星存图
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int head[100000];
int dfn[100000];
int low[100000];
int ans[100000];
struct EdgeNode
{
int to;
int w;
int next;
}e[100000];//用链式向前星存图
int cont,cnt,root;
void add(int from,int to)
{
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}//用链式向前星存图
void init()
{
cont=0;
cnt=1;
root=1;
memset(head,-1,sizeof(head));
memset(ans,0,sizeof(ans));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
}//初始化
void Tarjan(int u,int from)
{
dfn[u]=low[u]=cnt;
cnt++;
int sum=0;
for(int k=head[u];k!=-1;k=e[k].next)
{
int v=e[k].to;
if(dfn[v]==0)
{
Tarjan(v,u);//向下搜
low[u]=min(low[u],low[v]);//更新最小时间戳
if(u==root)
{
sum++;
if(sum>1)ans[u]=1;
}//第一种情况,当根节点有不止一棵子树时,该根节点为一个割点
if(low[v]>=dfn[u]&&u!=root)
{
ans[u]=1;
}//第二种情况,非根节点u的子节点v,只能通过节点u,找到u的祖先节点时,节点u为一个割点
}
else if(v!=from)low[u]=min(low[u],dfn[v]);//如果不是在走回头路更新最小时间戳
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==0)break;
init();
int u;
while(~scanf("%d",&u))
{
if(u==0)break;
int v;
char tmp;
scanf("%c",&tmp);
while(tmp!='\n')//当敲回车时,跳出循环,进入下一组关系
{
scanf("%d%c",&v,&tmp);
add(u,v);
add(v,u);
}
}
Tarjan(1,-1);//从节点一开始搜索
int output=0;
for(int i=1;i<=n;i++)
{
if(ans[i]==1)
{
output++;
}//每遇到一个割点,答案加一
}
printf("%d\n",output);
}
}