题目描述:
有一些学校连接到一个计算机网络。这些学校之间达成了一个协议:每个学校维护着一个学
校列表,它向学校列表中的学校发布软件。注意,如果学校B在学校A的列表中,则A不一定在
B的列表中。
任务A:计算为使得每个学校都能通过网络收到软件,你至少需要准备多少份软件拷贝。
任务B:考虑一个更长远的任务,想确保给任意一个学校发放一个新的软件拷贝,该软件拷
贝能发布到网络中的每个学校。为了达到这个目标,必须在列表中增加新成员。计算需要添加新
成员的最小数目。
// 任务A就是求缩点后 入度为0的点的个数
// 任务B 就是让缩点后的图中出度或入度为0的点消失 那么只要出度为0的点和入度为0的点连 主要看哪种点多就是了
#include <iostream> #include <algorithm> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <string.h> using namespace std; #define MOD 1000000007 #define maxn 60100 #define maxm 10010 struct Edge{ int to; int next; Edge(){}; Edge(int u,int v){to=u;next=v;} }E[maxn]; stack<int> S; int V[maxm],num; int belong[maxm]; int pre[maxm]; int dfst,scc; int ans; bool tag[maxm]; int in[maxm],out[maxm]; void init(int n){ dfst=scc=0; num=0; ans=0; while(!S.empty()) S.pop(); for(int i=1;i<=n;i++){ V[i]=-1; pre[i]=0; belong[i]=0; } } void add(int u,int v){ E[num].to=v; E[num].next=V[u]; V[u]=num++; } int tarjan(int u){ int lowu=pre[u]=++dfst; int v,e; S.push(u); for(e=V[u];e!=-1;e=E[e].next){ v=E[e].to; if(!pre[v]){ int lowv=tarjan(v); lowu=min(lowu,lowv); } else if(!belong[v]) lowu=min(lowu,pre[v]); } if(lowu==pre[u]){ scc++; for(;;){ int x=S.top();S.pop(); belong[x]=scc; if(x==u) break; } } return lowu; } int main() { int n,m,T; int u,v; int i,j=1; //scanf("%d",&T); while(scanf("%d",&n)!=EOF){ // scanf("%d",&m); init(n); for(i=1;i<=n;i++){ u=i; while(scanf("%d",&v),v){ add(u,v); } } for(i=1;i<=n;i++) if(!pre[i]) tarjan(i); // for(i=1;i<=n;i++) printf("%d ",belong[i]); for(i=1;i<=scc;i++) out[i]=0,in[i]=0; int e,u,v; for(i=1;i<=n;i++) { for(e=V[i];e!=-1;e=E[e].next){ u=belong[i]; v=belong[E[e].to]; if(u!=v){ in[v]++; out[u]++;//,printf("v=%d ",v); }
} } int A=0,B=0; for(i=1;i<=scc;i++){ if(!in[i]) A++; if(!out[i]) B++; } B=max(A,B); if(scc==1) B=0;// 特殊情况下 只有一个强连通分量 郁闷开始这里写成了n printf("%d\n%d\n",A,B); } return 0; }