Doves and bombs UVA - 10765
图论·双连通分量
题目大意:
给定一个n个点的连通的无向图,一个点的“鸽子值”定义为将它从图中删去后连通块的个数。求每个点的“鸽子值”。
题解:
就是求一个点包含在几个双连通分量里。
其实不用求出双联通分量,只要在dfs的时候碰到low[v]>=dfn[u]的时候统计一下答案即可。
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50005;
struct Edge{ int to,next; }e[N*2];
int head[N], ec;
void clearEdge(){ memset(head,0,sizeof(head)); ec=0; }
void add(int a,int b){ ec++; e[ec].to=b; e[ec].next=head[a]; head[a]=ec; }
struct Ans{
int id,val;
bool operator < (const Ans & tp) const {
return val > tp.val || (val==tp.val && id<tp.id);
}
}ans[N];
int low[N],dfn[N],tim;
int n,m;
void clear(){
clearEdge();
for(int i=1;i<=n;i++) ans[i].id=i, ans[i].val=1;
tim=0; memset(dfn,0,sizeof(dfn));
}
void dfs(int u,int f){
low[u]=dfn[u]=++tim; int child=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(!dfn[v]){
child++;
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]) ans[u].val++;
}
else if(dfn[v]<dfn[u] && v!=f)
low[u]=min(low[u],dfn[v]);
}
if(f<0 && child==1) ans[u].val=1;
}
int main(){
freopen("a.in","r",stdin);
while(~scanf("%d%d",&n,&m) && (n||m)){
int a,b;
clear();
while(~scanf("%d%d",&a,&b) && a>=0){
a++; b++;
add(a,b); add(b,a);
}
dfs(1,-1);
sort(ans+1,ans+1+n);
for(int i=1;i<=m;i++){
printf("%d %d\n",ans[i].id-1,ans[i].val);
}
puts("");
}
}