Zoj 1119 POJ 1523 SPF 求关节点及删除关节点会出现多少个连通分量 Tarjan算法
有最朴素的想法就是依次删除每个点,看剩下的图有多少个连通分量,如果只有一个,不是关节点(也叫割点),否则是关节点。
这种算法的复杂度是O(n^3).
这里的Tarjan算法的复杂度只有O(n^2),在连通图中只做一次DFS,根据DFS时遍历结点的先后顺序,依次给每个结点编号,这个编号叫该点的深度值,存在数组dfn[]中
求每个点的low[]值,low值是这样求的,每个点的low值最初就是该点的深度值。然后看该点的邻接点,如果该点的邻接点被访问过了,low值就是min(low[自己],dfn[邻接点])。
如果未被访问过,父结点的 low值=min(low[自己],low[子结点]),如果出现子结点的low值等于父结点的深度,那么说明该子结点最多只能到父结点,删掉父结点,子结点去不了父结点的祖先结点,换句话说,就是删掉父结点及与父结点相关联的边,这个图会不连通。
这么说吧,在DFS时,一个点如果是关节点,1:它是根结点,有>=2个孩子,那么删掉该点,图会不连通
2:它不是根结点,它的孩子结点除了通过它和它的祖先结点连通外没有其他的路径和它的祖先结点连通,那么显然删掉这个结点,图也不连通了。
贴代码:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #define MAXN 1005 4 bool edge[MAXN][MAXN];//邻接矩阵记录图 5 bool used[MAXN]; 6 int nodes;//最大结点数 7 int subnets[MAXN];//subnets[i]表示去掉节点i后的连通分支数 8 int dfn[MAXN];//DFS时该结点的深度 9 int low[MAXN];//每个顶点的low值,用来判断是否是关节点 10 int tmpdfn;//DFS时编顶点的深度值 11 int son; 12 int min(int x,int y) 13 { 14 return x<y ? x:y; 15 } 16 void init() 17 { 18 low[1] = dfn[1] = 1; 19 tmpdfn = 1; 20 son = 0; 21 memset(used,0,sizeof(used)); 22 used[1] = 1; 23 memset(subnets,0,sizeof(subnets)); 24 } 25 void DFS(int u) 26 { 27 for(int v=1; v<=nodes; ++v) 28 { 29 if(edge[u][v])//v与u相邻 30 { 31 if(used[v]) low[u] = min(low[u],dfn[v]);//这是一条回边 32 else//v是儿子结点 33 { 34 used[v] = 1; 35 dfn[v] = low[v] = ++tmpdfn; 36 DFS(v); 37 low[u] = min(low[u],low[v]);//儿子结点的low值和自己的low值中选小的 38 //儿子结点能到达哪里,父亲节点通过儿子结点到达。 39 if(low[v] == dfn[u]) 40 { 41 if(u == 1) son++; 42 else subnets[u]++; 43 } 44 } 45 } 46 } 47 } 48 void Tarjan() 49 { 50 bool flag = 0; 51 init(); 52 DFS(1); 53 if(son > 1) subnets[1] = son-1; 54 for(int i=1; i<= nodes; ++i) 55 { 56 if(subnets[i]) 57 { 58 flag = 1; 59 printf(" SPF node %d leaves %d subnets\n",i,subnets[i]+1); 60 } 61 } 62 if(!flag) printf(" No SPF nodes\n"); 63 } 64 int main() 65 { 66 // freopen("in.cpp","r",stdin); 67 int u,v,ser=0; 68 while(scanf("%d",&u)) 69 { 70 if(u==0) break; 71 memset(edge,0,sizeof(edge)); 72 nodes = 0; 73 scanf("%d",&v); 74 if(u>nodes) nodes = u; 75 if(v > nodes) nodes = v; 76 edge[u][v] = edge[v][u] = 1; 77 while(scanf("%d",&u)) 78 { 79 if(u == 0) break; 80 scanf("%d",&v); 81 if(u>nodes) nodes = u; 82 if(v>nodes) nodes = v; 83 edge[u][v] = edge[v][u] = 1; 84 } 85 if(ser > 0) puts(""); 86 printf("Network #%d\n",++ser); 87 Tarjan(); 88 } 89 return 0; 90 }