题意:求图中割点的数量,割点是指无向图中的一个点,满足删除与该点所连的边后原图中曾经相通的点不再连通。
题解:回忆Tarjan求SCC的过程,如果某个点u的某个儿子v及其子树中的所有点的low均大于等于dfn[u](即low[v]<=dfn[u]),那么v子树上的点只能通过u来到达其他节点,因此u是一个割点。同理如果low[v]>dfn[n],则v子树上的点只能通过(u,v)来到达其他节点,因此(u,v)是一条割边。
#include#include #include #include #include #include using namespace std;const int MAXN=100+2;const int MAXM=10000+2;struct HASH{ int u; HASH *next; HASH(){} HASH(int _u,HASH *_next):u(_u),next(_next){}}*table[MAXN],mem[2*MAXM];int N,cnt,ans;int dfn[MAXN],low[MAXN],depth,t;bool flag[MAXN],cut[MAXN];void Insert(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));}void Tarjan(int x){ dfn[x]=low[x]=++depth,flag[x]=1; for(HASH *p=table[x];p;p=p->next){ if(!dfn[p->u]){ Tarjan(p->u),low[x]=min(low[x],low[p->u]); if(low[p->u]>=dfn[x] && x!=1) cut[x]=1; else if(x==1) t++;//if(low[p->u]>dfn[x]) bridge++; } else low[x]=min(low[x],dfn[p->u]); }}int main(){ while(scanf("%d",&N)!=EOF && N){ t=ans=cnt=depth=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(cut,0,sizeof(cut)); memset(flag,0,sizeof(flag)); memset(table,0,sizeof(table)); int u,v; while(scanf("%d",&u) && u) while(getchar()!='\n'){ scanf("%d",&v); Insert(u,v),Insert(v,u); } Tarjan(1); for(int i=1;i<=N;i++) if(cut[i]) ans++; if(t>1) ans++; printf("%d\n",ans); } return 0;}