题意:
一个点能影响到之后的所有点,问最少给几个点施加影响能使所有的点都收到影响以及最少连几条线能使得给一个点施加影响就能使所有点都受到影响
思路:
第一个问就是求强连通分量的数量
第二问,我们需要求没有入度和没有出度的联通分量各有多少,取最大值即可。因为我们必须保证所有的联通分量间可达
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
const int maxn = 1e5 + 10;
int n,m,u,v,tot,top,cnt,flag;
int head[maxn],vis[maxn],s[maxn];
int dfn[maxn],low[maxn],belong[maxn];
int in[maxn],out[maxn];
struct Node
{
int v,next;
} edge[maxn];
void init()
{
tot = cnt = top = flag = 0;
memset(head,-1,sizeof head);
memset(dfn,0,sizeof dfn);
memset(vis,0,sizeof vis);
memset(in,0,sizeof in);
memset(out,0,sizeof out);
}
void add(int u,int v)
{
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void tarjan(int v)
{
dfn[v] = low[v] = ++flag;
vis[v] = 1;
s[top++] = v;
for(int i = head[v]; i!=-1; i = edge[i].next)
{
int j = edge[i].v;
if(!dfn[j])
{
tarjan(j);
low[v] = min(low[v],low[j]);
}
else if(vis[j])
{
low[v] = min(low[v],dfn[j]);
}
}
if(dfn[v] == low[v])
{
cnt++;
int t;
do
{
t = s[--top];
vis[t] = 0;
belong[t] = cnt;
}
while(t!=v);
}
}
void func()
{
for(int i = 1; i <= n; i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
}
int main()
{
ios::sync_with_stdio(0);
while(cin>>n)
{
init();
for(int i = 1; i <= n; i++)
{
cin>>v;
while(v)
{
add(i,v);
cin>>v;
}
}
func();
for(int i = 1; i <= n; i++)
{
for(int j = head[i]; j!= -1; j = edge[j].next)
{
if(belong[edge[j].v] != belong[i])
{
in[belong[edge[j].v]]++;
out[belong[i]]++;
}
}
}
int sumin = 0,sumout = 0;
for(int i = 1; i <= cnt; i++)
{
if(!in[i])sumin++;
if(!out[i]) sumout++;
}
cout<<sumin<<endl;
if(cnt==1) cout<<0<<endl;
else cout<<max(sumin,sumout)<<endl;
}
return 0;
}