【luogu2812】 校园网络

(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值