这题利用tarjan算法中的low[v]>=dfn[u]来判断割点,其位置放在回溯里。同时,要注意讨论根结点。
#include<stdio.h>
#include<string.h>
#define maxn 1002
int edge[maxn*maxn*2],first[maxn],next[maxn*maxn*2],tot,ans[maxn],vis[maxn],fa;
int dfn[maxn],low[maxn],index,n;
void add_edge(int u,int v)
{
edge[tot]=v;next[tot]=first[u];first[u]=tot++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++index;
int son=0;
for(int i=first[u];i!=-1;i=next[i])
{
if(!dfn[edge[i]])
{
tarjan(edge[i]);
if(low[u]>low[edge[i]])
low[u]=low[edge[i]];
if(low[edge[i]]>=dfn[u])son++;
}
else if(low[u]>dfn[edge[i]])
low[u]=dfn[edge[i]];
}
if(u!=fa)son++;
ans[u]=son;
}
void solve()
{
for(int i=n;i>=1;i--)
if(vis[i]&&!dfn[i])
tarjan(i);
}
int main()
{
int t=1;
int u,v;
while(~scanf("%d",&u)&&u)
{
tot=n=index=0;
memset(first,-1,sizeof(first));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
scanf("%d",&v);
vis[u]=1;
vis[v]=1;
if(n<u)n=u;
if(n<v)n=v;
add_edge(u,v);
add_edge(v,u);
while(1)
{
scanf("%d",&u);
if(!u)break;
scanf("%d",&v);
if(n<u)n=u;
if(n<v)n=v;
vis[u]=1;
vis[v]=1;
add_edge(u,v);
add_edge(v,u);
}
printf("Network #%d\n",t++);
fa=n;
solve();
int m=0;
for(int i=1;i<=n;i++)
if(ans[i]>1)
{
m++;
printf(" SPF node %d leaves %d subnets\n",i,ans[i]);
}
if(!m)
printf(" No SPF nodes\n");
printf("\n");
}
return 0;
}