【题意】
给定一个无向图,求若删除其中一个点,则最多能形成多少个连通分量。
【题解】
无向图求割点,tarjan算法。令cnt[i]为在以节点i为根的子树中,去除i,能形成多少个连通分量,则ans=max(cnt[i])+原有的连通分支数。
【代码】
#include <iostream>
#include <vector>
using namespace std;
const int maxn=10010;
int low[maxn],dfn[maxn],cnt[maxn],v[maxn];
vector<int> a[maxn];
int ans,tot,n,m,root;
void dfs(int x,int fa,int dep)
{
int i,ans=0,y,sum=0;
v[x]=1;
dfn[x]=low[x]=dep;
for (i=0;i<a[x].size();i++)
{
y=a[x][i];
if (v[y]==1 && y!=fa)
low[x]=min(low[x],dfn[y]);
if (v[y]==0)
{
sum++;
dfs(y,x,dep+1);
low[x]=min(low[x],low[y]);
if (x==root && sum>1 || x!=root && low[y]>=dfn[x])
cnt[x]++;
}
}
v[x]=2;
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int i,x,y;
while (scanf("%d%d",&n,&m)!=EOF)
{
if (n==0 && m==0) break;
memset(v,0,sizeof(v));
memset(cnt,0,sizeof(cnt));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
tot=ans=0;
for (i=0;i<n;i++)
a[i].clear();
for (i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
for (i=0;i<n;i++)
if (v[i]==0)
{
tot++;
root=i;
dfs(i,-1,1);
}
for (i=0;i<n;i++)
ans=max(ans,cnt[i]);
if (tot==n) cout << n-1 << endl;
else cout << ans+tot << endl;
}
return 0;
}