1. 程式人生 > >洛谷P2812 校園網絡[數據加強版] [Tarjan]

洛谷P2812 校園網絡[數據加強版] [Tarjan]

擴大 har fine 表示 tchar 得到 共享軟件 -c math

  題目傳送門

校園網絡

題目背景

浙江省的幾所OI強校的神犇發明了一種人工智能,可以AC任何題目,所以他們決定建立一個網絡來共享這個軟件。但是由於他們腦力勞動過多導致全身無力身體被♂掏♂空,他們來找你幫助他們。

題目描述

共有n所學校(n<=10000)已知他們實現設計好的網絡共m條線路,為了保證高速,網絡是單向的。現在請你告訴他們至少選幾所學校作為共享軟件的母機母雞,能使每所學校都可以用上。再告訴他們至少要添加幾條線路能使任意一所學校作為母機母雞都可以使別的學校使用上軟件。

輸入輸出格式

輸入格式:

第一行一個整數n。

接下來n行每行有若幹個整數,用空格空格隔開。

第i-1行的非零整數x,表示從i到x有一條線路。以0作為結束標誌。

輸出格式:

第一行一個整數表示問題1的答案。

第二行回答問題2.

輸入輸出樣例

輸入樣例#1:
5
2 0
4 0
5 0
1 0
0
輸出樣例#1:
2
2

說明

POJ原題。數據擴大了100倍。

邊數 $\leq 5000000$


  分析:

  $Tarjan$裸題。

  因為在一個強連通分量中的電腦可以相互傳遞信息,所以可以縮點。所點以後在重建邊,此時整張圖可能是一個非連通圖,那麽我們就查詢有哪些點入度為$0$,這些點就是母機(母雞)。然後我們再找入度為$0$的點和出度為$0$的點,取$max$就可以得到第二問的答案。因為只要把出度為$0$的點與入度為$0$的點依次連接就可以形成一個大環,這樣就能保證所有計算機都能相互到達了。(不過要特判只有一個強連通分量的情況,只有一個強連通分量的話就不需要再連邊,第二問答案也就是$0$)

  Code:

  

//It is made by HolseLee on 20th Aug 2018
//Luogu.org P2812
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<stack>
#define
Max(a,b) (a)>(b)?(a):(b) #define Min(a,b) (a)<(b)?(a):(b) using namespace std; const int N=1e4+7; int n,dfn[N],low[N],belong[N],scc,ans,idx,ru[N],chu[N]; bool vis[N]; vector<int>e[N]; stack<int>sta; inline int read() { char ch=getchar();int num=0;bool flag=false; while(ch<0||ch>9){if(ch==-)flag=true;ch=getchar();} while(ch>=0&&ch<=9){num=num*10+ch-0;ch=getchar();} return flag?-num:num; } void tarjan(int u) { dfn[u]=low[u]=++idx; vis[u]=true;sta.push(u); int v; for(int i=0;i<e[u].size();++i){ v=e[u][i]; if(!dfn[v]){ tarjan(v); low[u]=Min(low[u],low[v]); }else if(vis[v]){ low[u]=Min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ scc++; do{ v=sta.top();sta.pop(); vis[v]=false;belong[v]=scc; }while(v!=u); } } int main() { n=read(); int x; for(int i=1;i<=n;++i){ x=read(); while(x){ e[i].push_back(x); x=read(); } } for(int i=1;i<=n;++i) if(!dfn[i])tarjan(i); for(int i=1;i<=n;++i) for(int j=0;j<e[i].size();++j){ if(belong[i]!=belong[e[i][j]]) ++chu[belong[i]],++ru[belong[e[i][j]]]; } for(int i=1;i<=scc;++i) if(!ru[i])++ans; printf("%d\n",ans); int tot=0; for(int i=1;i<=scc;++i) if(!chu[i])++tot; ans=Max(ans,tot); if(scc==1)ans=0; printf("%d\n",ans); return 0; }

洛谷P2812 校園網絡[數據加強版] [Tarjan]