解析:
题意:求去掉任意一个节点后的所得图的联通分量数的最大值
利用tarjan求出割点,并记录割点的有效分支数(即去掉割点后该分支成为一个联通分量)
单独处理根节点;特判m = 0时的情况。
AC Code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10000 + 10;
const int maxm = 1e6+10;
int n,m;
int head[maxn];
int dfn[maxn];
int low[maxn];
int get[maxn];//增加的联通分支数
int index = 1;
int tot;
int root;
struct Edge
{
int to,next;
}edge[maxm];
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void tarjan(int f, int u)
{
dfn[u] = low[u] = index++;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(dfn[v] == -1)
{
tarjan(f,v);
low[u] = min(low[u],low[v]);
if(low[v] >= dfn[u] && u != f) get[u]++;
else if(u == f) root ++;
}
else low[u] = min(low[u],dfn[v]);
}
}
void init()
{
memset(head,-1,sizeof(head));
memset(dfn,-1,sizeof(dfn));
memset(get,0,sizeof(get));
index = 1;
tot = 0;
}
void solve()
{
int ans = 0;
int s = 0;
for(int i = 0; i < n; i++)
if(dfn[i] == -1)
{
s++;
root = 0;
tarjan(i,i);
if(root > 1) ans = max(ans,root);
}
if(ans != 0) ans = s + ans - 1;
ans = max(ans,s);
for(int i = 0; i < n; i++)
{
if(get[i] > 0)
ans = max(ans,s+get[i]);
}
printf("%d\n",ans);
}
int main()
{
while(scanf("%d%d",&n,&m) && n)
{
init();
int u,v;
if(m==0) {printf("%d\n",n-1);continue;}
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
solve();
}
return 0;
}