题目描述
传送门
题意:无向图求割点数以及去掉这个割点了之后形成的连通块个数。
题解
ans[x]表示的是x点的后代能形成的连通块个数。如果x为第一个访问的点,那么连通块个数即为ans[x],如果x不是第一个访问的点,那么连通块个数为ans[x]+1,也就是说加上了来的时候的那个连通块。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 500005
int n,m,x,y,dfs_clock,Case;
int tot,point[1005],nxt[N*2],v[N*2];
int dfn[1005],low[1005],ans[1005];
bool flag;
void clear()
{
n=m=x=y=dfs_clock=tot=flag=0;
memset(v,0,sizeof(v));memset(point,0,sizeof(point));memset(nxt,0,sizeof(nxt));
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(ans,0,sizeof(ans));
}
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int x)
{
dfn[x]=low[x]=++dfs_clock;
for (int i=point[x];i;i=nxt[i])
if (!dfn[v[i]])
{
tarjan(v[i]);
low[x]=min(low[x],low[v[i]]);
if (dfn[x]<=low[v[i]]) ans[x]++;
}
else low[x]=min(low[x],dfn[v[i]]);
}
int main()
{
while (1)
{
clear();
m=0;
while (1)
{
scanf("%d",&x);if (!x) break;
scanf("%d",&y);m++;add(x,y);
n=max(n,x);n=max(n,y);
}
if (!m) break;
tarjan(1);
printf("Network #%d\n",++Case);
flag=false;
for (int i=1;i<=n;++i)
if (i==1&&ans[i]>1)
{
flag=true;
printf(" SPF node %d leaves %d subnets\n",i,ans[i]);
}
else if (i!=1&&ans[i]+1>1)
{
flag=true;
printf(" SPF node %d leaves %d subnets\n",i,ans[i]+1);
}
if (!flag) puts(" No SPF nodes");
putchar('\n');
}
}