/*
构建一棵dfs树,序列dfn[i]为深度优先数,表示dfs时访问i节点的序号,low[i]表示从i节点出发能访问到的最小的深度优先数。
当且仅当节点u满足如下两个条件之一时,u为割点:
1.u为dfs树的根,且u至少有两个子节点。
2.u不是dfs树的根,至少存在一个节点v是u的子节点,且low[v]>=dfn[u]。
若u为割点,记subnets[u]为u的子节点数,则去掉u后,图被分成subnets[u]+1个部分(每个子节点的部分和u的祖先的部分),若u为dfs树的根,则分成subnets[u]个部分(根节点没有祖先)。
以上全部算法均在dfs过程中完成。
*/
#define N 1010
struct edge{
int v;
int next;
}e[N*5];
int ecnt;
int head[N];
void init(){
ecnt = 0;
memset(head,-1,sizeof(head));
}
void add(int u,int v){
e[ecnt].v = v;
e[ecnt].next = head[u];
head[u] = ecnt++;
e[ecnt].v = u;
e[ecnt].next = head[v];
head[v] = ecnt++;
}
int low[N],dfn[N];
int cut[N];
int n,m;
int t;
int ans;
int sub[N];
//tarjan求无向图双连通图
void tarjan(int u,int fa){
low[u] = dfn[u] = ++t;
int i;
for(i=head[u];i!=-1;i=e[i].next){
int v = e[i].v;
if(v == fa)continue;
if(!dfn[v]){
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(dfn[u]<=low[v]){//u是割点
if(u!=1)sub[u]++;//假定1为根结点
else ans++;
}
} else low[u] = min(low[u],dfn[v]);//返祖边
}
}
int main(){
int a,b;
int ca=1;
while(1){
scanf("%d",&a);
if(!a)break;
init();
memset(dfn,0,sizeof(dfn));
scanf("%d",&b);
add(a,b);
int node = 0;
node = max(a,b);
while(scanf("%d",&a) && a){
scanf("%d",&b);
add(a,b);
node = max(node,max(a,b));
}
int i,j;
ans=t=0;
memset(sub,0,sizeof(sub));
tarjan(1,1);//假定1为根结点
if(ca>1)puts("");
printf("Network #%d\n",ca++);cout<<ans<<endl;
if(ans>1)sub[1] = ans-1;//根至少有两个儿子才算是割点
bool ok=0;
for(i=1;i<=node;i++){
if(sub[i]){
ok = 1;
printf(" SPF node %d leaves %d subnets\n",i,sub[i]+1);
}
}
if(!ok)puts(" No SPF nodes");
}
return 0;
}