题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26780
思路:判断一个点是否是割点的两个条件:1、如果一个点v是根结点并且它的子女个数大于等于2,则v是割点。2、如果点v不是根结点,并且存在她的一个子女u,使得low[u]>=dfn[v],则v是割点。然后我发现以前求割点的写法有点问题,=.=//。幸好不是在比赛中遇到!贡献上最新模板。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 44444 struct Edge{
int v,next;
}edge[MAXN<<]; int n,m,NE;
int head[MAXN]; void Insert(int u,int v)
{
edge[NE].v=v;
edge[NE].next=head[u];
head[u]=NE++;
} int cnt,ans;
int low[MAXN],dfn[MAXN];
bool mark[MAXN]; bool is_cutpoint[MAXN];
void Tarjan(int root,int u)
{
int rt_son=;
low[u]=dfn[u]=++cnt;
mark[u]=true;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(dfn[v]==){
Tarjan(root,v);
low[u]=min(low[u],low[v]);
if(u!=root&&low[v]>=dfn[u])is_cutpoint[u]=true;
rt_son++;
}else if(mark[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(u==root&&rt_son>=){
is_cutpoint[u]=true;
}
} int main()
{
int _case,u,v,t=;
scanf("%d",&_case);
while(_case--){
scanf("%d%d",&n,&m);
NE=;
memset(head,-,sizeof(head));
while(m--){
scanf("%d%d",&u,&v);
Insert(u,v);
Insert(v,u);
}
cnt=ans=;
memset(mark,false,sizeof(mark));
memset(dfn,,sizeof(dfn));
memset(is_cutpoint,false,sizeof(is_cutpoint));
for(int i=;i<=n;i++){
if(dfn[i]==)Tarjan(i,i);
}
for(int i=;i<=n;i++)if(is_cutpoint[i])ans++;
printf("Case %d: %d\n",t++,ans);
}
return ;
}