题目链接:http://poj.org/problem?id=1523
SPF:A Single Point of Failure也就是割点(一个点导致网络之间的不连通),由于给出的图是无向图,所以只要连通就一定强连通。要求连通分支的数量就是要求请联通分支的数量,我们可想到tarjan求强连通的步骤,只要一群结点的low值相同他们就是属于同一个SCC(Strongly Connected Component),所以我们只要对于每一个割点,记录一下这个点所到的其他结点的不相同的low值的数量,就是这个点能够将网络分成的连通分支的数量。因为在dfs树上,如果一个根结点是割点的话,对于他的每一个子节点,我们进行一次深搜(没访问过的),并且标记访问,表上记号,等到所有的子结点全部搜完就记号的数量就是强连通分量的个数。
代码如下:
1 #include<cstdio> 2 #include<string.h> 3 #include<set> 4 #include<iostream> 5 using namespace std; 6 const int maxn =1e3+10; 7 int head[maxn],nxt[maxn],iscut[maxn],dfn[maxn],low[maxn]; 8 bool vis[maxn]; 9 struct node{ 10 int u,v; 11 }p[maxn]; 12 int e; 13 int n,cnt; 14 void addedge(int u,int v) 15 { 16 p[e].u=u; 17 p[e].v=v; 18 nxt[e]=head[u]; 19 head[u]=e++; 20 } 21 void tarjan(int u,int fa) 22 { 23 dfn[u]=low[u]=++cnt;//dfn为dfs时间戳,low为回退边指向的最小祖先 24 int child=0; 25 for(int i=head[u];~i;i=nxt[i]) 26 { 27 int v=p[i].v; 28 if(!dfn[v]) 29 { 30 tarjan(v,u); 31 low[u]=min(low[u],low[v]); 32 child++; 33 if(u!=1&&low[v]>=dfn[u])iscut[u]=1; 34 } 35 else if(dfn[v]<dfn[u]&&v!=fa)//回退边 36 { 37 low[u]=min(low[u],dfn[v]); 38 } 39 } 40 if(u==1&&child>=2)iscut[1]=1; 41 } 42 int main() 43 { 44 int x,y; 45 int step=0; 46 while(scanf("%d",&x)&&x) 47 { 48 scanf("%d",&y); 49 n=0; 50 memset(head,-1,sizeof(head)); 51 memset(nxt,-1,sizeof(nxt)); 52 memset(dfn,0,sizeof(dfn)); 53 memset(low,0,sizeof(low)); 54 memset(iscut,0,sizeof(iscut)); 55 memset(vis,0,sizeof(vis)); 56 cnt=0; 57 e=0; 58 n=max(max(x,y),n); 59 addedge(x,y);addedge(y,x); 60 while(scanf("%d",&x)&&x) 61 { 62 scanf("%d",&y); 63 n=max(max(x,y),n); 64 addedge(x,y);addedge(y,x); 65 } 66 tarjan(1,-1);//从结点一开始建立dfs树 67 set<int> s; 68 bool flag=false; 69 printf("Network #%d\n",++step); 70 for(int i=1;i<=n;i++) 71 { 72 s.clear(); 73 if(iscut[i])//对于每一个割点查找连通分量的数量 74 { 75 flag=true; 76 for(int j=head[i];~j;j=nxt[j]) 77 { 78 s.insert(low[p[j].v]);//搜索不同的low值数量 79 } 80 } 81 if(s.size()) 82 printf(" SPF node %d leaves %d subnets\n",i,s.size()); 83 } 84 if(!flag)printf(" No SPF nodes\n"); 85 printf("\n"); 86 } 87 }