(http://www.elijahqi.win/2017/07/03/%E3%80%90luogu2812%E3%80%91-%E6%A0%A1%E5%9B%AD%E7%BD%91%E7%BB%9C/%20%E2%80%8E)
题目背景
浙江省的几所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倍。 POJ原题 USACO schlnet
#include<cstdio>
#include<cstring>
#define N 11000
int num1,num,h[N],s,stack[N],dfn[N],low[N],top,b[N];
bool stackf[N];
struct node{
int x,y,next;
}data[110000];
int max(int x,int y){
return x>y?x:y;
}
int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar();}
return x;
}
void insert1(int x,int y){
data[++num].x=x;data[num].y=y;data[num].next=h[x];h[x]=num;
}
void tarjan(int u){
dfn[u]=++num;low[u]=num;stack[++top]=u;stackf[u]=true;
for (int i=h[u];i;i=data[i].next){
int v=data[i].y;
if (dfn[v]==0){
tarjan(v);
if (low[v]<low[u]) low[u]=low[v];
}else{
if (stackf[v]&&dfn[v]<low[u]) low[u]=dfn[v];
}
}
if (dfn[u]==low[u]){
++s;int y;
do{
y=stack[top--];
b[y]=s;stackf[y]=false;
}while (y!=u);
}
}
int main(){
//freopen("2812.in","r",stdin);
//freopen("2812.out","w",stdout);
int n=read();num=top=0;
for (int i=1;i<=n;++i){
int x=read();
while (x!=0){
insert1(i,x);x=read();
}
}
num1=num;num=0;
memset(stackf,false,sizeof(stackf));
memset(dfn,0,sizeof(dfn));
for (int i=1;i<=n;++i)
if (dfn[i]==0) tarjan(i);
//for (int i=1;i<=n;++i) printf("%d ",b[i]);
//a1 为出边 a2为入边
int a1[N],a2[N];
for (int i=1;i<=num;++i){
int x=data[i].x,y=data[i].y;
if (b[x]!=b[y]){
a1[b[x]]++;a2[b[y]]++;
}
}
int ans=0,ans1=0;
for (int i=1;i<=s;++i) if (a1[i]==0) ans++;
printf("%d\n",ans);
for (int i=1;i<=s;++i) if(a2[i]==0) ans1++;
printf("%d",max(ans,ans1));
return 0;
}