浙江省的幾所OI強校的神犇發明了一種人工智能,可以AC任何題目,所以他們決定建立一個網絡來共享這個軟件。但是由於他們腦力勞動過多導致全身無力身體被♂掏♂空,他們來找你幫助他們。
共有n所學校(n<=10000)已知他們實現設計好的網絡共m條線路,爲了保證高速,網絡是單向的。現在請你告訴他們至少選幾所學校作爲共享軟件的母機~~母雞,能使每所學校都可以用上。再告訴他們至少要添加幾條線路能使任意一所學校作爲母機母雞~~都可以使別的學校使用上軟件。
前置知識:
分析
這道題的話,我們先考慮縮短。
不會縮點的可以看一下我的文章
既然我們縮好點了,那麼整張圖變成了一個 (有向無環圖)
這樣就好處理了。
-
對於問題
A
我們發現既然這整張圖是 ,那麼答案顯然爲入度爲 的點的個數
-
對於問題
B
我們發現這整張圖是 。我們要把它變成連通圖。連通圖需要滿足:
- 沒有入度爲 的點
- 沒有出度爲 的點
考慮入度爲 和 出度爲 的點兩兩匹配,則需要匹配 次。
一些細節
注意縮點後只有一個點的情況,本身就是連通的,所以 問題 B
的答案爲
#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar('0'+x%10);
}
const int MAXN=1e6+10,MAXM=1e6+10;
int s[MAXN],stop,dfn[MAXN],low[MAXN],scccnt,sccnum[MAXN],dfscnt,tot,he[MAXN],ne[MAXM<<1],ed[MAXM<<1],n,x,se,es,du[MAXN],ud[MAXN];
void add(int x,int y){
ed[++tot]=y;
ne[tot]=he[x];
he[x]=tot;
}
inline void tarjan(int now){
dfn[now]=low[now]=++dfscnt;
s[stop++]=now;
for (int i=he[now];i;i=ne[i]){
if(!dfn[ed[i]]){
tarjan(ed[i]);
low[now]=min(low[now],low[ed[i]]);
}else if(!sccnum[ed[i]]){
low[now]=min(low[now],dfn[ed[i]]);
}
}
if(dfn[now]==low[now]){
scccnt++;
do{
sccnum[s[--stop]]=scccnt;
}while(s[stop]!=now);
}
}//tarjin的板子
int main(){
read(n);
for(int i=1;i<=n;i++)
while(cin>>x&&x)add(i,x);
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=n;i++)
for(int j=he[i];j;j=ne[j])
if(sccnum[i]!=sccnum[ed[j]]){
du[sccnum[ed[j]]]++;//統計
ud[sccnum[i]]++;//統計
}
for(int i=1;i<=scccnt;i++){
if(!du[i])se++;//入度爲0的點
if(!ud[i])es++;//出度爲0的點
}
cout<<se<<endl<<(scccnt==1?0:max(se,es));//小細節
return 0;
}