题意翻译成人话就是
求图中连通块中几个点入度为0(也就是没法从根部接受信息,也可以理解成有几个联通块)。
再看任务 B ,显然如果全图连通就是0,我们的目的是将整个图搞成联通,那么统计入度和出度的最小值,就是我们需要添加几个入度才能让整个图连通了。
以下是 AC 代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
int n,a;
struct edge
{
int nxt,to;
}ed[maxn*30];
int head[maxn*30],cnt;
void add(int a,int b)
{
ed[++cnt].to = b;
ed[cnt].nxt = head[a];
head[a] = cnt;
}
int in[maxn],ot[maxn],id[maxn];
int dfn[maxn],low[maxn],idx,tot;
int stk[maxn],top;
bool instk[maxn];
void tarjan(int s)
{
dfn[s] = low[s] = ++idx;
stk[++top] = s;
instk[s] = true;
for(int i=head[s];i;i=ed[i].nxt)
{
int t = ed[i].to;
if(!dfn[t])
{
tarjan(t);
low[s] = min(low[s], low[t]);
}
else if(instk[t]) low[s] = min(low[s], dfn[t]);
}
int k;
if(dfn[s] == low[s])
{
tot ++;
do{
k = stk[top--];
instk[k] = false;
id[k] = tot;
}while(k != s);
}
}
int main()
{
n = read();
memset(instk, false, sizeof instk);
memset(in, 0, sizeof in); memset(ot, 0, sizeof ot);
for(int i=1;i<=n;i++)
{
a = read();
while(a!=0)
{
add(i, a);
a = read();
}
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=ed[j].nxt)
{
int t = ed[j].to;
if(id[t] != id[i])
{
ot[id[i]] ++;
in[id[t]] ++;
}
}
}
int sum_in = 0, sum_ot = 0;
for(int i=1;i<=tot;i++)
{
if(in[i] == 0)
sum_in ++;
if(ot[i] == 0)
sum_ot ++;
}
if(tot == 1)
printf("1\n0\n");
else
printf("%d\n%d\n",sum_in,max(sum_in,sum_ot));
return 0;
}