题意:给出一个图,一个点的“鸽子值”是删掉这个点后有多少个连通分量。求出每个点的鸽子值。
思路:如果一个点不是割顶,那么连通分量还是1,如果是割顶,那么连通分量的数目就是包含这个割顶的双连通分量的个数。所以直接模板吧。
代码:
#include<iostream>
#include<cstring>
#include<string.h>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 10000+5;
vector<int> G[maxn];
int pre[maxn] , dfs_clock;
int n , m;
struct Ans
{
Ans() { i = -1 ; cnt = 0; }
int i;
int cnt;
}is_cut[maxn];
bool cmp(const Ans & a1 , const Ans & a2)
{
if (a1.cnt==a2.cnt) return a1.i < a2.i;
return a1.cnt > a2.cnt;
}
int dfs(int u,int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = 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]) {
is_cut[u].i = u;
is_cut[u].cnt++;
}
}
else if (pre[u] > pre[v]) lowu = min(lowu,pre[v]);
}
if (fa < 0 && child==1) {
is_cut[u].i = u;
is_cut[u].cnt = 1;
}
return lowu;
}
void init()
{
dfs_clock = 0;
memset(pre,0,sizeof(pre));
for (int i = 0 ; i < n ; ++i) G[i].clear();
}
void input()
{
int u , v;
while (scanf("%d%d",&u,&v))
{
if (u==-1 && v==-1) return;
G[u].push_back(v);
G[v].push_back(u);
}
}
void solve()
{
for (int i = 0 ; i < n ; ++i) {
is_cut[i].i = i;
is_cut[i].cnt = 1;
}
is_cut[0].cnt = 0;
dfs(0,-1);
sort(is_cut,is_cut+n,cmp);
for (int i = 0 ; i < m ; ++i) printf("%d %d\n",is_cut[i].i,is_cut[i].cnt);
cout << endl;
}
int main()
{
while (scanf("%d%d",&n,&m),n+m)
{
init();
input();
solve();
}
}