测试地址:Electricity
题目大意:给定一个无向图(注意:不一定连通),问从里面去掉一个顶点以及与其相连的所有边之后,整个图被划分成的连通块的最大数目。
做法:本题需要用到点双连通分量的知识。
什么叫点双连通分量呢?首先,一个无向图是点双连通的,就代表将这个图中任意一点去掉,剩下的图仍能连通,那么类比强连通和强连通分量的定义,不难得出点双连通分量的定义:对一个无向图
定义了解之后,对于这一题我们分析一下,一般来说一个顶点只从属于一个点双连通分量,而割点可以从属于多个点双连通分量,我们知道将割点从图中去掉之后,图就会被分为多个连通块,而被分成的连通块的数目正好就是这个割点从属的点双连通分量的数目。那么怎么算出一个割点从属的点双连通分量数目呢?很简单,假设点
然而本题还没有结束,注意到原图可能不连通,那么设原图有
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,tot,tim,ans,rt,first[10010],dfn[10010],low[10010];
struct edge {int v,next;} e[2000010];
bool vis[10010];
void insert(int a,int b)
{
e[++tot].v=b;
e[tot].next=first[a];
first[a]=tot;
}
void dfs(int v)
{
vis[v]=1;
dfn[v]=++tim;
low[v]=dfn[v];
int s=1;
for(int i=first[v];i;i=e[i].next)
{
if (!vis[e[i].v])
{
dfs(e[i].v);
if (low[e[i].v]>=dfn[v]) s++;
low[v]=min(low[v],low[e[i].v]);
}
else low[v]=min(low[v],dfn[e[i].v]);
}
if (v!=rt) ans=max(ans,s);
if (v==rt) ans=max(ans,s-1);
}
void tarjan()
{
memset(vis,0,sizeof(vis));
tim=0;
int cnt=0;
for(int i=0;i<n;i++)
if (!vis[i])
{
cnt++;
rt=i;
dfs(i);
}
ans+=cnt-1;
}
int main()
{
while(scanf("%d%d",&n,&m)&&n)
{
memset(first,0,sizeof(first));
tot=0;
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
insert(a,b),insert(b,a);
}
ans=0;
tarjan();
printf("%d
",ans);
}
return 0;
}