这是一道双倍经验的题!!!
题目背景
浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件。但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们。
题目描述
共有n所学校(n<=10000)已知他们实现设计好的网络共m条线路,为了保证高速,网络是单向的。现在请你告诉他们至少选几所学校作为共享软件的母机母鸡,能使每所学校都可以用上。再告诉他们至少要添加几条线路能使任意一所学校作为母机母鸡都可以使别的学校使用上软件。
输入输出格式
输入格式:
第一行一个整数n。
接下来n行每行有若干个整数,用空格空格隔开。
第i-1行的非零整数x,表示从i到x有一条线路。以0作为结束标志。
输出格式:
第一行一个整数表示问题1的答案。
第二行回答问题2.
输入输出样例
说明
POJ原题。数据扩大了100倍。
边数 leq5000000≤5000000
其实这题........
原版就是刻录光盘的加钱版.........
这个加强版反而是原版的水题版QAQ(我这个代码两个都能过)
那么接下来说一下细微的差别:
问题 1 是选取最少数量的母机来使每个学校都用上。我们对于这个问题,不难想的吧,解法就是求出所有入度为 0 的点。
简单说一下原因:
如果入度为 0 的点不是信息出发点,那么这个点必定不会接收到任何节点发出的信息,因为它的入度为 0 。
并且假设信息出发点不是入度为0的点,那么其必有入度点,使其覆盖点更多,而我们要找至少多少个点。
那么结论显然是正确的。
问题 2 是至少要添加几条线路,才能使任意一所学校作为母机都可以使别的学校用上。(这个手玩一下就发现了啊)
剩下的看我上一篇题解就好了啊
放上代码,我滚了。
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 #include<algorithm> 6 #include<stack> 7 using namespace std; 8 9 const int MA=1e4+1; 10 int n,m,inn,ouu; 11 int in[MA],ou[MA]; 12 int ecnt,head[MA]; 13 int ti,low[MA],dfn[MA]; 14 bool vis[MA]; 15 int cnt[MA],col[MA]; 16 struct ss{ 17 int to,nxt; 18 }d[5000001]; 19 stack<int> q; 20 21 inline void add(int a,int b) { 22 d[++ecnt].nxt=head[a]; 23 d[ecnt].to=b; 24 head[a]=ecnt; 25 return; 26 } 27 28 inline int read() { 29 int x=0;char ch=getchar(); 30 while(ch<'0'||ch>'9')ch=getchar(); 31 while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); 32 return x; 33 } 34 35 void init() { 36 n=read(); 37 for(int i=1;i<=n;i++) { 38 bool flag=0; 39 while(1) { 40 if(flag==1) { 41 flag=0; 42 continue; 43 } 44 int a=read(); 45 if(a==0) { 46 flag=1; 47 break; 48 } 49 add(i,a); 50 } 51 } 52 return; 53 } 54 55 void Tar(int now) { 56 dfn[now]=low[now]=++ti; 57 q.push(now); 58 vis[now]=1; 59 for(int i=head[now];i;i=d[i].nxt) { 60 int nx=d[i].to; 61 if(!dfn[nx]) { 62 Tar(nx); 63 low[now]=min(low[now],low[nx]); 64 } 65 else if(vis[nx]) low[now]=min(low[now],dfn[nx]); 66 } 67 if(low[now]==dfn[now]) { 68 ++m; 69 while(now!=q.top()) { 70 int a=q.top(); 71 q.pop(); 72 vis[a]=0; 73 ++cnt[m]; 74 col[a]=m; 75 } 76 q.pop(); 77 vis[now]=0; 78 col[now]=m; 79 ++cnt[m]; 80 } 81 } 82 83 void print() { 84 for(int i=1;i<=n;i++){ 85 for(int j=head[i];j;j=d[j].nxt){ 86 if(col[i]!=col[d[j].to]){ 87 ++ou[col[i]]; 88 ++in[col[d[j].to]]; 89 } 90 } 91 } 92 for(int i=1;i<=m;i++) { 93 if(!in[i]) inn++; 94 if(!ou[i]) ouu++; 95 } 96 if(m==1) printf("%d %d",inn,0); 97 else printf("%d %d",inn,max(inn,ouu)); 98 return; 99 } 100 101 int main() 102 { 103 init(); 104 for(int i=1;i<=n;i++) 105 if(!dfn[i]) Tar(i); 106 print(); 107 return 0; 108 }
谢谢!