题解 P7251 【[JSOI2014] 强连通图】

P7251 [JSOI2014] 强连通图

题目大意:

给定个图,回答两个问题:

  1. 求图中最大的强连通分量的大小
  2. 求添加多少条边可使图强连通。

solution:

\(1\) 非常好实现,直接 \(\text{tarjan}\) 求强联通分量后取
\(\max \limits_{i=1}^{cnt\_scc}\{\text{size[ i ]}\}\) 。考虑 \(2\) 。一个强连通图必然没有入度为 \(0\) 和出度为 \(0\) 的点(点数大于 \(1\) ),在缩点后,我们只需要统计入度和出度为 \(0\)强连通分量的个数再取个 \(\max\) 就好了。

接下来是细节的处理:

在上文叙述中括号中的条件需要特判,即 \(\text{cnt\_scc}==1\) 时,最大的强连通分量大小只有 \(1\) 且不用加边即是强连通图。输出:

1
0

看到这的同学,可以自己去写代码了(tf口吻)

代码
#include<cstdio>
using namespace std;
const int N=1e5+5,M=3e5+5;
int hd[N],nt[M],to[M],cnt;
int dfn[N],low[N],of[N],st[N],size[N],top,lcnt,chuo;
int ru[N],chu[N],ans;
bool vis[N];
inline int Min(int a,int b){return a<=b?a:b;}
inline int Max(int a,int b){return a>=b?a:b;}
inline void tian(int a,int b){
	to[++cnt]=b,nt[cnt]=hd[a],hd[a]=cnt;
}
inline void tarjan(int x){
	st[++top]=x, vis[x]=1;
	dfn[x]=++chuo,low[x]=chuo;
	for(int i=hd[x];i;i=nt[i]){
		int y=to[i];
		if(!dfn[y]){
			tarjan(y);
			low[x]=Min(low[x],low[y]);
		}
		else if(vis[y]) low[x]=Min(low[x],dfn[y]);
	}
	if(dfn[x]==low[x]){
		lcnt++;
		while(1){
			int y=st[top--];
			of[y]=lcnt,vis[y]=0;
			size[lcnt]++;
			ans=Max(ans,size[lcnt]);
			if(x==y) break;
		}
	}
}
int main(){
	int n,m; scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y; scanf("%d%d",&x,&y);
		tian(x,y);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) tarjan(i);
	if(lcnt==1){
		printf("1\n0");
		return 0;
	}
	for(int x=1;x<=n;x++){
		for(int i=hd[x];i;i=nt[i]){
			int y=to[i];
			if(of[x]!=of[y])
				chu[of[x]]++,ru[of[y]]++;
		}
	}
	int rcnt=0,ccnt=0;
	for(int i=1;i<=lcnt;i++){
		if(!ru[i]) rcnt++;
		if(!chu[i]) ccnt++;
	}
	printf("%d\n%d",ans,Max(rcnt,ccnt));
	return 0;
}

End

posted @ 2021-07-29 19:32  Mr_think  阅读(69)  评论(0)    收藏  举报