<题目链接>
题目大意:
给出一个无向图,求出其中的割点数量。
解题分析:
无向图求割点模板题。
一个顶点u是割点,当且仅当满足
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。(也就是说V没办法绕过 u 点到达比 u dfn要小的点)
注:这里所说的树是指,DFS下的搜索树。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int M =1e4+10; 6 int dfn[M],low[M],father[M],head[M]; 7 int n,m,tot,top,cnt; 8 struct EDGE{ 9 int to,next; 10 }edge[M]; 11 void init(){ 12 memset(head,-1,sizeof(head)); 13 memset(low,0,sizeof(low)); 14 memset(dfn,0,sizeof(dfn)); 15 memset(father,0,sizeof(father)); 16 tot=cnt=0; 17 } 18 void add(int u,int v){ 19 edge[++cnt].to=v,edge[cnt].next=head[u]; 20 head[u]=cnt; 21 } 22 void Targan(int u,int fa){ 23 dfn[u]=low[u]=++tot; 24 father[u]=fa; //记录每个节点的父亲 25 for(int i=head[u];~i;i=edge[i].next){ 26 int v=edge[i].to; 27 if(!dfn[v]){ 28 Targan(v,u); 29 low[u]=min(low[u],low[v]); 30 } 31 else if(fa!=v){ 32 low[u]=min(dfn[v],low[u]); 33 } 34 } 35 } 36 void solve(){ 37 int rootson=0,ans=0; 38 bool cut[M]={false}; //标记该点是否为割点 39 Targan(1,-1); //从1开始遍历整张图 40 for(int i=2;i<=n;i++){ 41 int u=father[i]; 42 if(u==1)rootson++; //父亲为根节点,则根节点的分支+1 43 else if(dfn[u]<=low[i])cut[u]=true; //说明i无法绕过它的父亲节点到达比dfn[u]更小的节点,说明u为割点 44 } 45 for(int i=2;i<=n;i++){ 46 if(cut[i])ans++; 47 } 48 if(rootson>1)ans++; //如果根节点的子树数>1,则说明该根节点是割点 49 printf("%d ",ans); 50 } 51 int main(){ 52 while(scanf("%d",&n)!=EOF,n){ 53 init(); 54 int u,v; 55 char ch; 56 while(scanf("%d",&u),u){ 57 while(scanf("%d%c",&v,&ch)){ 58 add(u,v),add(v,u); 59 if(ch==' ')break; 60 } 61 } 62 solve(); 63 } 64 }
2018-10-17