【題目描述】
A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.
Input
The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.
Output
Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
2
【題目分析】
有一些學校,現在他們之間可以存在發送軟件的關系
A. 問最少給幾個學校發送軟件就可以讓所有學校受到軟件
B. 問最少加多少條邊后給任意學校發送軟件所有的學校都可以收到軟件
我們進行強連通分量縮點建圖之后統計所有入度為0和出度為0的點,入度為0 的點的數目就是A問題的答案。
對于B問題,答案是入度為0的點和出度為0的點的較大值。
原因我在網上沒有找到答案,大家都說答案就是較大值,可是我卻一直不太能理解。后來覺得可能存在數學證明什么的可以證明這樣一定存在一種方式可以將一個DAG變成一個強連通分量。
我自己的理解的話,首先我們將所有出度為0的點連在不能到達該點的入度為0的點上,最后肯定會形成一個環,通過這個環所有的點都可以相互到達,而剩下的入度為0 的點或者出度為0 的點可以隨意連在其他點上,這樣就將一個DAG變化為一個強連通圖
需要注意的是如果原本的圖就是一個強連通圖就不要加邊,需要特判。
【AC代碼】
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<climits>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;typedef long long ll;
const int MAXN=1e2+5;
const int MAXM=1e4+5;struct node
{int v,next;
}Edge[MAXM];
int head[MAXN],tot;
int DFN[MAXN],LOW[MAXN];
int color[MAXN],cnt;
bool vis[MAXN];
int idx;
int stack[MAXN],top;
int In[MAXN],Out[MAXN];
int n;
int ans1,ans2,ans3;
int Case=0;void init()
{memset(head,0,sizeof(head)); tot=0;idx=0; memset(vis,0,sizeof(vis));memset(DFN,0,sizeof(DFN));memset(color,0,sizeof(color));cnt=0; top=0;memset(In,0,sizeof(In));memset(Out,0,sizeof(Out));
}void AddEdge(int u,int v)
{tot++;Edge[tot].v=v; Edge[tot].next=head[u];head[u]=tot;
}void read()
{int u,v;for(int i=1;i<=n;i++){while(~scanf("%d",&v) && v){AddEdge(i,v);}}
}void Trajan(int x)
{int v,tmp;DFN[x]=LOW[x]=++idx;stack[++top]=x; vis[x]=true;for(int i=head[x];i;i=Edge[i].next){v=Edge[i].v;if(!DFN[v]){Trajan(v);if(LOW[v]<LOW[x]) LOW[x]=LOW[v];}else if(vis[v] && DFN[v]<LOW[x]){LOW[x]=DFN[v]; }}if(DFN[x]==LOW[x]){cnt++;do{tmp=stack[top--];vis[tmp]=false;color[tmp]=cnt;}while (tmp!=x);}
}void solve()
{int v;for(int i=1;i<=n;i++){if(!DFN[i])Trajan(i);}for(int i=1;i<=n;i++){for(int j=head[i];j;j=Edge[j].next){v=Edge[j].v;if(color[i]!=color[v]){In[color[v]]++;Out[color[i]]++;}}}ans1=0; ans2=0;int minc;for(int i=1;i<=cnt;i++){if(!In[i]){ans1++;}if(!Out[i]){ans2++;}}if(cnt==1) ans3=0;else ans3=max(ans1,ans2);printf("%d\n%d\n",ans1,ans3);
}int main()
{while(~scanf("%d",&n) && n){init();read();solve();}return 0;
}