***割点概念:去掉一个点后图不连通,该点就为割点
割点满足的条件:
一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=122091#problem/B***
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<cstring> #include<vector> using namespace std; #define N 100005 int n; int dfn[N], low[N], Father[N]; int Time; vector<vector<int> > G; void Init() { G.clear(); G.resize(n+5); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(Father, 0, sizeof(Father)); Time=0; } void Tarjan(int u, int fa) { dfn[u]=low[u]=++Time; Father[u]=fa; int len=G[u].size(), v; for(int i=0; i<len; i++) { v=G[u][i]; if(!dfn[v]) { Tarjan(v, u); low[u]=min(low[u], low[v]); } else if(fa!=v) low[u]=min(low[u], dfn[v]); } } void solve() { int RootSon=0, ans=0, v; bool Cut[N]= {false}; for(int i=1; i<=n; i++) { if(!low[i]) Tarjan(i, 0); } for(int i=2; i<=n; i++) { v=Father[i]; if(v==1) RootSon++; else if(dfn[v]<=low[i]) Cut[v]=true; } for(int i=2; i<=n; i++) { if(Cut[i]) ans++; } if(RootSon>1) ans++; printf("%d ", ans); } int main() { while(scanf("%d", &n), n) { Init(); int a, b; char ch; while(scanf("%d", &a), a) { while(scanf("%d%c", &b, &ch)) { G[a].push_back(b); G[b].push_back(a); if(ch==' ') break; } } solve(); } return 0; }