题目描述:
分析
第一问很显然,把强连通分量缩成一个点之后,图中剩下多少个入度为0的点,就需要发放多少次软件(这些点没有其他点给他分享),对于入度不为0的点,就一定会从到达它的点向它分享软件。
第二问其实问的就是把一个图,通过连边的方式,缩成一个强连通分量,至少需要多少条边。那么有一个很直观的思路:对于每一个入度为0的点,必须向它连一条边,同样的,对于每一个出度为0的点,必须从它连出去一条边。设有n个入读为0的点,m个出度为0的点,至此,我们能够确定的最小连边数量就是max(n,m)条。
注:这里所说的最小连边数量并不是指只连这么多条边就能满足题意,而是说答案的最小值为max(n,m),换句话说,答案一定不小于这个值。
之后为了讲解方便,我们将入度为0的点成为A类点。
将出度为0的点成为B类点。
接下来,我们需要找一种合理的连图方式,使得连的边数刚好为max(n,m)条。首先,考虑简单一点的情况,假设n=m,很容易想到,
对任意一个B类点i,向一个无法达到i的A类点j相连接,这样一来,凡是能到达i的点,都能够到达j能到达的点。最后,任意一个能到达原B类点的点(其实就是所有点),都能够到达任意一点。
如果不存在无法达到i的A类点,那么说明任意一个点都能到达i,这种情况下,i向任意一个A类点连接都没问题。
现在,再来考虑考虑n≠m的问题
其实很简单,如果A类点多了,就先将多的那些A类点依次连接,最后形成一个n=m的图。
同理,如果B类点多了,也是将多余的B依次连接即可。
转移成n=m的图,需要消耗|n-m|条边,最后再消耗min(n,m)条边即可。
综上,答案就是max(n,m)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 110
using namespace std;
int dfn[MAXN],low[MAXN],cnt,tot,sum,nx[MAXN];
vector<int> a[MAXN];
stack<int> s;
pair<int,int> l[MAXN*MAXN];
int in[MAXN],out[MAXN];
void dfs(int x){
dfn[x]=++cnt;
low[x]=dfn[x];
s.push(x);
for(int i=0;i<a[x].size();i++){
if(dfn[a[x][i]]==0){
dfs(a[x][i]);
low[x]=min(low[x],low[a[x][i]]);
}
else
if(nx[a[x][i]]==0)
low[x]=min(low[x],dfn[a[x][i]]);
}
if(low[x]==dfn[x]){
sum++;
while(s.top()!=x){
nx[s.top()]=sum;
s.pop();
}
nx[s.top()]=sum;
s.pop();
}
}
int n;
int main(){
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
SF("%d",&n);
int x,y;
for(int i=1;i<=n;i++){
SF("%d",&x);
while(x){
a[i].push_back(x);
l[++tot]=make_pair(i,x);
SF("%d",&x);
}
}
for(int i=1;i<=n;i++)
if(dfn[i]==0)
dfs(i);
/*PF("(%d)\n",sum);
for(int i=1;i<=n;i++)
PF("[%d:%d]\n",i,nx[i]);*/
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=1;i<=tot;i++){
x=nx[l[i].first];
y=nx[l[i].second];
//PF("(%d %d)\n",x,y);
if(x!=y)
a[x].push_back(y);
}
for(int i=1;i<=sum;i++){
out[i]=a[i].size();
for(int j=0;j<a[i].size();j++)
in[a[i][j]]++;
}
int ans1=0,ans2=0;
if(sum==1){
PF("1\n0");
return 0;
}
for(int i=1;i<=sum;i++){
if(in[i]==0)
ans1++;
if(out[i]==0)
ans2++;
}
PF("%d\n%d",ans1,max(ans1,ans2));
}