【洛谷 2812】校园网络

题目背景

浙江省的几所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

一个比较简单的tarjian缩点,因为一个强连通分块里面可以互相到达,那么可以当成一个点处理。

任务A:

需要求最多在多少学校发送新软件,其实就是求缩点后入度为0的个数(如果入度不为0就可以从其他学校传过来)

任务B:

求入度为0的点数与出度为0的点的较大值

#include<bits/stdc++.h>
using namespace std; int a[110][110]={0},l[110][110]={0},n; int in[110]={0},out[110]={0},team[110]={0}; int ins=0,outs=0,sum=0; inline void init() { scanf("%d",&n); for(int i=1;i<=n;i++) { int t; scanf("%d",&t); while(t>0) { a[i][t]=l[i][t]=1; in[t]++;//需要记录入度和出度 out[i]++; scanf("%d",&t); } } return; } inline void floyed() { for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=a[i][j]||(a[i][k]&&a[k][j]); return; } inline void work() { memset(team,-1,sizeof(team)); for(int i=1;i<=n;i++) { if(team[i]==-1)//如果i点未涂色 team[i]=i;//涂色 else { in[team[i]]+=in[i];//i所属的强联通分量入度加上i的入度 out[team[i]]+=out[i];//出度同理 } for(int j=1;j<=n;j++)//这里每个点都要搜一遍 if(a[i][j]&&a[j][i])//如果i,j属于同一强联通分量 { team[j]=team[i];//涂色 if(l[i][j])//如果i,j直接有边相连 { in[team[i]]--;//i所属的强联通分量入度-1 out[team[i]]--;//出度同理 } } } return; } inline void print() { for(int i=1;i<=n;i++) if(team[i]==i)//搜索缩点后的各个点 { sum++;//强连通分量数 if(in[i]==0)ins++;//入度为0的点数 if(out[i]==0)outs++;//出度为0的点数 } if(sum==1)printf("1\n0");//如果只有一个强联通分量 else printf("%d\n%d",ins,max(ins,outs)); return; } int main() { init(); floyed(); work(); print(); return 0; }

转载于:https://www.cnblogs.com/Le-mon/p/7718683.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值