题目大意:给一个n个点的无向连通图,找出删除某个点后的连通块个数。
题目分析:统计一下每个节点属于几个双连通分量,若是割点,得到的便是答案,否则答案为1。
代码如下:
# include<iostream> # include<cstdio> # include<stack> # include<vector> # include<cstring> # include<algorithm> using namespace std; # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)); const int N=10005; struct Edge { int u,v; Edge(int _u,int _v):u(_u),v(_v){} bool operator < (const Edge &a) const { if(v==a.v) return u<a.u; return v>a.v; } }; stack<Edge>S; vector<Edge>ans; vector<int>G[N],bcc[N]; int n,m,dfs_cnt,bcc_cnt,bccno[N],pre[N],low[N],cnt[N],iscut[N]; void dfs(int u,int fa) { low[u]=pre[u]=++dfs_cnt; int child=0; REP(i,0,G[u].size()){ int v=G[u][i]; if(pre[v]==0){ ++child; S.push(Edge(u,v)); dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>=pre[u]){ iscut[u]=1; bcc[++bcc_cnt].clear(); while(1){ Edge x=S.top(); S.pop(); if(bccno[x.u]!=bcc_cnt){ bcc[bcc_cnt].push_back(x.u); bccno[x.u]=bcc_cnt; }if(bccno[x.v]!=bcc_cnt){ bcc[bcc_cnt].push_back(x.v); bccno[x.v]=bcc_cnt; } if(x.u==u&&x.v==v) break; } } }else if(pre[v]<pre[u]&&v!=fa){ S.push(Edge(u,v)); low[u]=min(low[u],pre[v]); } } if(fa<0&&child==1) iscut[u]=0; } void findBcc() { CL(bccno,0); CL(iscut,0); CL(pre,0); dfs_cnt=bcc_cnt=0; REP(i,0,n) if(!pre[i]) dfs(i,-1); } int main() { int a,b; while(scanf("%d%d",&n,&m)&&(n+m)) { REP(i,0,n) G[i].clear(); while(scanf("%d%d",&a,&b)) { if(a==-1&&b==-1) break; G[a].push_back(b); G[b].push_back(a); } findBcc(); ans.clear(); CL(cnt,0); REP(i,1,bcc_cnt+1) REP(j,0,bcc[i].size()) ++cnt[bcc[i][j]]; REP(i,0,n){ if(iscut[i]) ans.push_back(Edge(i,cnt[i])); else ans.push_back(Edge(i,1)); } sort(ans.begin(),ans.end()); REP(i,0,m) printf("%d %d ",ans[i].u,ans[i].v); printf(" "); } return 0; }