题目链接:poj1144
方法:图论 割点
思想:对于图中的一个顶点,如果删除它,图就会被分割成至少两个分离的子图,
那么该顶点就是割点。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
int times,root;
int visit[105],flag[105];
int low[105],dfn[105];
vector <int> map[105];
int min(int a,int b)
{ return a<b?a:b; }
void dfs(int v)
{
int i,w,cnum=0;//cnum 表示孩子的个数
times++;
visit[v]=1;
dfn[v]=low[v]=times; //记录时间戳
for(i=0;i<map[v].size();i++)
{
w=map[v][i];
if(!visit[w])//没有被访问过,则w是v的孩子结点
{
cnum++;
dfs(w);
low[v]=min(low[w],low[v]);
if(v==root&&cnum==2)
flag[v]=1;//如果v是根,且有2个以上的孩子,则是割点
if(v!=root&&low[w]>=dfn[v])
flag[v]=1;//不为根若low[w]>=dfn[v],则是割点
}
else if(v!=w)
{//w已经访问过了,说明从v到w有一条回边,w是v的祖先
low[v]=min(low[v],dfn[w]);
}
}
}
int main()
{
int n;
while(scanf("%d",&n)==1&&n)
{
int a,b;
int i,ans=0;
char c;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(visit,0,sizeof(visit));
memset(flag,0,sizeof(flag));
for(i=0;i<=n;i++)map[i].clear();
while(scanf("%d",&a)==1&&a)
{
while((c=getchar())!='\n')
{
scanf("%d",&b);
map[a].push_back(b);
map[b].push_back(a);
}
}
times=0;root=1;
dfs(root);
for(i=1;i<=n;i++)
if(flag[i])ans++;
printf("%d\n",ans);
}
return 0;
}