题目链接:https://vjudge.net/contest/166461#problem/B

题意:

给一个无向图,求每一个点删除后,剩下的连通块的数目;

分析:

只有割顶被删掉后,连通分量才会改变,改变多少呢? 就是他这个割顶除 父亲结点,的其他孩子结点(及其子孙结点)是否返回到最早的祖先结点(lowv) <= low[u];再加上原图的连通块;

WA了很多次,错误地方有两个;

1、板子抄错了,low 函数没有用子孙结点更新;

2、即时不是割顶,也要加入结果中,就当是他删掉后,连通分量没有改变;

#include <bits/stdc++.h>

using namespace std;

const int maxn = +;
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=;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 = ,num = ;
for(int i=; 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<&&child==) {
iscut[u] = ;
num = ;
}
//if(iscut[u])
ans.push_back(make_pair(u,num));
low[u] = lowu;
return lowu;
} void find_bcc(int n) {
memset(pre,,sizeof(pre));
memset(iscut,,sizeof(iscut));
memset(low,,sizeof(low));
dfs_clock = bcc_cnt = ;
for(int i=; i<n; i++)
if(!pre[i]) {
bcc_cnt++;
dfs(i,-);
}
} void print_ans() {
sort(ans.begin(),ans.end(),cmp);
for(int i=; i<m; i++)
printf("%d %d\n",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==-) break;
sol.AddEdge(u,v);
}
sol.find_bcc(n);
sol.print_ans();
} return ;
}
05-23 07:03