1. 程式人生 > 其它 >題解 P7251 【[JSOI2014] 強連通圖】

題解 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