POJ1523 Tarjan求割点以及删除割点之后强连通分量的数量

题目链接: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 }

 

上一篇:hdu1074之状压dp


下一篇:题解 P1057 【传球游戏】