关于割点的内容参考这篇文章:http://www.byvoid.com/en/blog/biconnect/
/* 1、若深度优先生成树的根有两棵或两棵以上的子树,则此根顶点必定为关节点。*/
/* 2、若生成树中某个非叶子顶点v,其孩子结点均没有指向 v 的祖先的回边,则 v 为关节点。*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=1010;
struct edge
{
int v,next;
}es[maxn];
int dfn[maxn],low[maxn],head[maxn],idx,n,f;
vector<pair<int,int> >ans;
void init(){
ans.clear();
for (int i=1;i<=maxn;++i){
head[i]=-1;
}
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
idx=0;
}
void tarjan(int u,bool root){
dfn[u]=low[u]=++idx;
int cnt=0;
for (int ne=head[u];ne!=-1;ne=es[ne].next){
int v=es[ne].v;
if(!dfn[v]){
tarjan(v,false);
low[u]=min(low[u],low[v]);
if(root){//根节点特判
cnt++;
}
else if(low[v]>=dfn[u]){//当前点是割点
cnt++;//子树数量
}
}else{//回边,已经和其他节点构成了分支,不再计算
low[u]=min(low[u],dfn[v]);
}
}
if(root&&cnt>=2){
ans.push_back(make_pair(u,cnt));
}else if(!root&&cnt){
ans.push_back(make_pair(u,cnt+1));
}
}
void addEdge(int u,int v,int eidx){
es[eidx].v=v;
es[eidx].next=head[u];
head[u]=eidx;
}
int main(){
int u,v,cas=1;
scanf("%d",&u);
while (1){
init();
scanf("%d",&v);
int eidx=0;
addEdge(u,v,eidx++);
addEdge(v,u,eidx++);
while (scanf("%d",&u)&&u){
scanf("%d",&v);
addEdge(u,v,eidx++);
addEdge(v,u,eidx++);
}
printf("Network #%d\n",cas++);
f=0;
tarjan(1,true);
sort(ans.begin(),ans.end());
if(ans.size()==0){
printf(" No SPF nodes\n");
}else{
for (int i=0;i<ans.size();++i){
printf(" SPF node %d leaves %d subnets\n",ans[i].first,ans[i].second);
}
}
scanf("%d",&u);
if(u==0)break;
printf("\n");
}
return 0;
}