AcWing 1183. 电力(无向图的双连通分量)

题目

给定一个由 n 个点 m 条边构成的无向图,请你求出该图删除一个点之后,连通块最多有多少。

输入格式

输入包含多组数据。

每组数据第一行包含两个整数 n,m。

接下来 m 行,每行包含两个整数 a,b,表示 a,b 两点之间有边连接。

数据保证无重边。

点的编号从 0 到 n−1。

读入以一行 0 0 结束。

输出格式

每组数据输出一个结果,占一行,表示连通块的最大数量。

数据范围

1≤n≤10000,
0≤m≤15000,
0≤a,b<n

思路

求割点,如果没有割点那答案就是连通块的个数,否则,就是删去割点后连通块的个数。我们需要用个数组存一下删除此点后可以加的连通块的个数。如果不是根节点那么就要加1.

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;

const int N=1e4+7,M=6e4+7; 

int n,m;
int h[N],e[M],ne[M],idx;
int dfn[N],low[N],timestamp;
int ans,root;

void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
	dfn[u]=low[u]=++timestamp;
	int cnt=0;
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
		if(!dfn[j])
		{
			tarjan(j);
			low[u]=min(low[u],low[j]);
			if(low[j]>=dfn[u])  cnt++;
		}
		else low[u]=min(low[u],dfn[j]);
	}
	if(u!=root) cnt++;
	ans=max(ans,cnt) ;
}

int main()
{
	//freopen("test.in","r",stdin);//设置 cin scanf 这些输入流都从 test.in中读取
    //freopen("test.out","w",stdout);//设置 cout printf 这些输出流都输出到 test.out里面去
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	while(cin>>n>>m,(n||m))
	{
		memset(dfn,0,sizeof dfn);
		memset(h,-1,sizeof h);
		idx=timestamp=0;
		while(m--)
		{
			int a,b;
			cin>>a>>b;
			add(a,b),add(b,a);
		}
		ans=0;
		int cnt=0;
		for(root=0;root<n;root++)
		{
			if(!dfn[root])
			{
				cnt++;
				tarjan(root);
			}
		}
		cout<<ans+cnt-1<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44828887/article/details/107367802
今日推荐