题意:一共n割点,然后若干行,每行第一个输入一个点,然后若干个点表示与他相连,0单独一行表示一个样例的结束。然后求图中的割点个数
割点:去掉该点之后得到的图不在连通,那么该店就是割点
一般割点有两种情况:1、父节点,当有两个或两个以上儿子节点的时候 2、dfn[x]表示深搜是x点是第几个开始搜索的,low[x]表示x及其父节点所能指向的最早的祖先,这个边官方就做回边,也就是回边往上能最高能到哪。如果 low[x] >= dfn[x] 也就是说x他的儿子们最多到x甚至还在x的下面,所以x就是割点,去掉x时候,x的儿子们就和x的上面的祖先们失去了联系
然后就是对low[u]的更新:普通情况下,就是u->v,然后v没有没访问,所以low[u] = min( low[u], low[v]) 另一中情况就是回边的情况,u->v然而v已经访问完了,说明v在上面,u是下面的,u是指向祖先的。此时 low[u] = min( low[u], dfn[v]);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int Max = 105; 8 vector<int> g[Max]; 9 int vis[Max],low[Max],pre[Max],iscut[Max]; 10 int n,root,time; 11 int get_min(int x, int y) 12 { 13 if(x > y) 14 return y; 15 return x; 16 } 17 void dfs(int u) 18 { 19 int child = 0; 20 pre[u] = low[u] = ++time; 21 vis[u] = 1; 22 int len = g[u].size(); 23 for(int i = 0; i < len; i++) 24 { 25 int w = g[u][i]; 26 if(!vis[w]) 27 { 28 child++; 29 dfs(w); 30 low[u] = get_min(low[u], low[w]); 31 if(u == root && child == 2) //根节点如果有两个以上儿子节点就是割点 32 iscut[u] = 1; 33 if(u != root && low[w] >= pre[u]) //u的子孙节点如果指向的最早节点还比u要大的话,u也是割点 34 iscut[u] = 1; 35 } 36 else if(w != u) // 这是应该避免重点的情况吗? 37 low[u] = get_min(low[u], pre[w]); 38 } 39 } 40 int main() 41 { 42 while (scanf("%d", &n) != EOF && n) 43 { 44 int a, b; 45 for(int i = 0; i <= n; i++) 46 g[i].clear(); 47 while(scanf("%d", &a) && a) 48 { 49 char ch; 50 while ( (ch = getchar()) != ' ') 51 { 52 scanf("%d", &b); 53 g[a].push_back(b); 54 g[b].push_back(a); 55 } 56 } 57 memset(pre, 0, sizeof(pre)); 58 memset(vis, 0, sizeof(vis)); 59 memset(low, 0, sizeof(low)); 60 memset(iscut, 0, sizeof(iscut)); 61 time = 0; 62 root = 1; 63 dfs(1); 64 int ans = 0; 65 for(int i = 1; i <= n; i++) 66 if(iscut[i]) 67 ans++; 68 printf("%d ", ans); 69 } 70 }