题目大意:给定的通信设备之间的关系,问有没有割点,并输出去掉割点后的连通分量的个数。
思路:裸的Trajan求解割点,当某个点为割点的条件是low[v]>=dfn[u],或者是根节点且孩子的数目>=2。连通分量的个数=符合条件孩子数目+1.
#include<map>
#include<queue>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
#define LL long long
#define inf 0x3f3f3f3f
const double PI=acos(-1.0);
using namespace std;
bool mp[1010][1010],vis[1010];
int n,m,cnt,dfn[1010],low[1010],son,subnet[1010],sum;
void init(){
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,false,sizeof(vis));
memset(subnet,0,sizeof(subnet));
son=0;sum=1;dfn[1]=low[1]=1;vis[1]=true;
}
int Tarjan(int x){
for(int i=1;i<=cnt;i++){
if(mp[x][i]){
if(!vis[i]){
vis[i]=true;
low[i]=dfn[i]=++sum;
Tarjan(i);
low[x]=min(low[x],low[i]);
if(low[i]>=dfn[x]){
if(x!=1)
subnet[x]++;
else
son++;
}
}
else
low[x]=min(low[x],dfn[i]);
}
}
}
int main(){
int i,j,k,a,b,cla=1;
while(~scanf("%d",&n)&&n){
cnt=0;
memset(mp,false,sizeof(mp));
scanf("%d",&m);
cnt=max(n,m);
mp[n][m]=mp[m][n]=true;
while(~scanf("%d",&a)&&a){
scanf("%d",&b);
mp[a][b]=mp[b][a]=true;
cnt=max(cnt,max(a,b));
}
printf("Network #%d\n",cla++);
init();
Tarjan(1);
bool bj=false;
if(son>1) subnet[1]=son-1;
for(i=1;i<=cnt;i++){
if(subnet[i]){
printf(" SPF node %d leaves %d subnets\n",i,subnet[i]+1);
bj=true;
}
}
if(!bj)
printf(" No SPF nodes\n");
printf("\n");
}
return 0;
}