题意:有N个学校,从每个学校都能从一个单向网络到另外一个学校。
1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
2:至少需要添加几条边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
解题关键:1、缩点之后求出入度为0的点的个数;
2、缩点之后入度为0点和出度为0点的个数的max,(因为是任意点可到达全图),若存在点到达全图,添加入度-1条边即可。
注意特判只有一个节点的情况。
dfn需要初始化
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 #define MAXN 120 10 #define MAXM 100010 11 struct edge{ 12 int to,nxt; 13 }e[MAXM]; 14 int degree1[MAXN],degree2[MAXN]; 15 int head[MAXN],st[MAXN],dfn[MAXN],lowest[MAXN],belong[MAXN]; 16 bool inst[MAXN]; 17 int n,scnt,top,tot;//scnt从1开始 18 void init(){ 19 memset(head,-1,sizeof head); 20 memset(degree1,0,sizeof degree1); 21 memset(degree2,0,sizeof degree2); 22 scnt=top=tot=0; 23 } 24 25 void add_edge(int u, int v){ 26 e[tot].to=v; 27 e[tot].nxt=head[u]; 28 head[u]=tot++; 29 } 30 31 void Tarjan(int u){ 32 dfn[u]=lowest[u]=++tot; 33 inst[u]=1; 34 st[top++]=u; 35 for(int i=head[u];i!=-1;i=e[i].nxt){ 36 int v=e[i].to; 37 if(!dfn[v]){ 38 Tarjan(v); 39 lowest[u]=min(lowest[u],lowest[v]); 40 } 41 else if(inst[v]){ 42 lowest[u]=min(lowest[u],dfn[v]);//也可用lowest 43 } 44 } 45 if(dfn[u]==lowest[u]){ 46 scnt++; 47 int t; 48 do{ 49 t=st[--top]; 50 inst[t]=false; 51 belong[t]=scnt; 52 }while(t!=u); 53 } 54 } 55 56 void solve(){//缩点 57 for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); 58 for(int i=1;i<=n;i++){ 59 for(int j=head[i];j!=-1;j=e[j].nxt){ 60 if(belong[i]!=belong[e[j].to]){ 61 degree1[belong[i]]++,degree2[belong[e[j].to]]++; 62 } 63 } 64 } 65 int sum1=0,sum2=0; 66 for(int i=1;i<=scnt;i++){ 67 if(!degree1[i]) sum1++; 68 if(!degree2[i]) sum2++; 69 } 70 if(scnt==1){//1个节点进行特判 71 printf("1 0 "); 72 return; 73 } 74 printf("%d ",sum2); 75 printf("%d ",max(sum1,sum2)); 76 return; 77 } 78 79 int main(){ 80 int a; 81 while(scanf("%d",&n)!=EOF){ 82 init(); 83 int m=1; 84 while(scanf("%d",&a)){ 85 if(a==0){ 86 m++; 87 if(m>n) break; 88 continue; 89 } 90 add_edge(m,a); 91 } 92 solve(); 93 } 94 return 0; 95 }