要判定一个结点u是不是割点的方法是
dfs树中
①u是根结点,如果u有两个及其以上的孩子(因为是dfs,所以如果有两个孩子,那么这两个孩子只通过u连接到一起),那么u是割点
②u不是根结点,如果u的后代的时间戳能够比u的时间戳小,即u的后代有边能够连回u的祖先,那么u不是割点(即low[v] < pre[u]),反之,u是割点(即low[v] >= pre[u])
定义pre[u] 为结点u搜索的次序编号(时间戳)
low[u]为u或者u的子树能够访问到的最小次序号,
low[u] = min
{
pre[u],
pre[v], (u,v)为后向边
low[v] (u,v)为树枝边,u为v的父亲
}
poj 1523
题意:如果某个点是割点,求删除该点后,将图分成了几个联通块。

1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 using namespace std; 5 6 const int N = 1000 + 10; 7 vector<int> G[N]; 8 int pre[N],iscut[N],dfs_clock; 9 int max(const int &a, const int &b) 10 { 11 return a > b ? a : b; 12 } 13 int min(const int &a, const int &b) 14 { 15 return a < b ? a : b; 16 } 17 18 int dfs(int u, int fa) 19 { 20 int lowu = pre[u] = ++dfs_clock; 21 int child = 0; 22 for(int i=0; i<G[u].size(); ++i) 23 { 24 int v = G[u][i]; 25 if(!pre[v]) 26 { 27 child ++; 28 int lowv = dfs(v,u); 29 lowu = min(lowu,lowv); 30 if(lowv >= pre[u]) 31 iscut[u]++;//找出结点u有多少个孩子不能连回自己的祖先,如果是找割点,那么iscut[u] = ture;即可 32 } 33 else if(v!=fa && pre[v] < pre[u])//v!=fa说明不能是反向边,而是后向边 34 lowu = min(lowu,pre[v]); 35 } 36 if(fa<0 && child>=1) iscut[u] = child-1;//dfs树,根结点的特判 37 return lowu; 38 } 39 int main() 40 { 41 int a,b,n,i; 42 int tCase = 1; 43 while(true) 44 { 45 for(i=0; i<N; ++i) 46 { 47 pre[i] = iscut[i] = 0; 48 G[i].clear(); 49 } 50 dfs_clock = 0; 51 scanf("%d",&a); 52 if(a==0) 53 break; 54 scanf("%d",&b); 55 n = max(a,b); 56 G[a].push_back(b); 57 G[b].push_back(a); 58 while(true) 59 { 60 scanf("%d",&a); 61 if(a==0) 62 break; 63 scanf("%d",&b); 64 n = max(n,a); 65 n = max(n,b); 66 G[a].push_back(b); 67 G[b].push_back(a); 68 } 69 if(tCase > 1) 70 puts(""); 71 dfs(1,-1); 72 printf("Network #%d ",tCase++); 73 bool find = false; 74 for(i=1; i<=n; ++i) 75 { 76 if(iscut[i] != 0) 77 { 78 find = true; 79 printf(" SPF node %d leaves %d subnets ",i,iscut[i]+1); 80 } 81 } 82 if(!find) 83 puts(" No SPF nodes"); 84 85 } 86 return 0; 87 }