题目链接:https://vjudge.net/contest/166461#problem/B
题意:
给一个无向图,求每一个点删除后,剩下的连通块的数目;
分析:
只有割顶被删掉后,连通分量才会改变,改变多少呢? 就是他这个割顶除 父亲结点,的其他孩子结点(及其子孙结点)是否返回到最早的祖先结点(lowv) <= low[u];再加上原图的连通块;
WA了很多次,错误地方有两个;
1、板子抄错了,low 函数没有用子孙结点更新;
2、即时不是割顶,也要加入结果中,就当是他删掉后,连通分量没有改变;
#include <bits/stdc++.h> using namespace std; const int maxn = 10000+5; int n,m; bool cmp(pair<int,int> a,pair<int,int> b) { if(a.second == b.second) return a.first < b.first; return a.second > b.second; } struct Sol { int pre[maxn],iscut[maxn],dfs_clock,bcc_cnt,low[maxn]; vector<int> G[maxn]; vector<pair<int,int> > ans; void init(int n) { for(int i=0;i<=n;i++) G[i].clear(); ans.clear(); } void AddEdge(int from,int to) { G[from].push_back(to); G[to].push_back(from); } int dfs(int u,int fa) { int lowu = pre[u] = ++dfs_clock; int child = 0,num = 0; for(int i=0; i<G[u].size(); i++) { int v = G[u][i]; if(v==fa) continue; if(!pre[v]) { child++; int lowv = dfs(v,u); lowu = min(lowu,lowv); if(lowv>=pre[u]) { iscut[u] = true; num++; } } else if(pre[v]<pre[u]) { lowu = min(lowu,pre[v]); } } if(fa<0&&child==1) { iscut[u] = 0; num = 0; } //if(iscut[u]) ans.push_back(make_pair(u,num)); low[u] = lowu; return lowu; } void find_bcc(int n) { memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut)); memset(low,0,sizeof(low)); dfs_clock = bcc_cnt = 0; for(int i=0; i<n; i++) if(!pre[i]) { bcc_cnt++; dfs(i,-1); } } void print_ans() { sort(ans.begin(),ans.end(),cmp); for(int i=0; i<m; i++) printf("%d %d ",ans[i].first,ans[i].second+bcc_cnt); puts(""); } } sol; int main() { while(scanf("%d%d",&n,&m),n) { sol.init(n); int u,v; while(true) { scanf("%d%d",&u,&v); if(u==-1) break; sol.AddEdge(u,v); } sol.find_bcc(n); sol.print_ans(); } return 0; }