题意:一个无向连通图删除某点后分成的连通块个数成为该点的鸽子值。求鸽子值最大的m个点的鸽子值
思路:1.鸽子值>1 <=> 该点是割点。2统计割点所连接的点双连通分量。tarjan算法求割点过程中,改标记割点为统计该点所连接的点双连通分量个数即可。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#define maxn 10010
#define INF 1<<28
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
vector<int> g[maxn];
int n,m,low[maxn],pre[maxn],dfs_clock;
struct Cut{
int num,id;
}cut[maxn];
bool cmp(Cut a,Cut b){ return a.num==b.num?a.id<b.id:a.num>b.num; }
void dfs(int u,int fa){
low[u]=pre[u]=++dfs_clock;
int child=0;
for(int i=0;i<g[u].size();i++)
if(!pre[g[u][i]]){
child++;
dfs(g[u][i],u);
low[u]=min(low[u],low[g[u][i]]);
if(low[g[u][i]]>=pre[u]) cut[u].num++;
}
else if(pre[g[u][i]]<pre[u]&&g[u][i]!=fa) low[u]=min(low[u],pre[g[u][i]]);
if(fa<0&&child==1) cut[u].num=0;
}
void find_cutvertex(){
mem(pre,0),dfs_clock=0;
for(int i=0;i<n;i++) if(!pre[i]) dfs(i,-1);
}
int main(){
//freopen("a.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF){
if(!n&&!m) break;
for(int i=0;i<n;i++) g[i].clear();
int u,v;
while(scanf("%d%d",&u,&v)!=EOF){
if(u==-1&&v==-1) break;
g[u].push_back(v),g[v].push_back(u);
}
for(int i=0;i<n;i++) cut[i].num=0,cut[i].id=i;
find_cutvertex();
sort(cut,cut+n,cmp);
for(int i=0;i<m;i++) printf("%d %d\n",cut[i].id,cut[i].num+1);
printf("\n");
}
return 0;
}