题目大意:
给出N个人,每个人都给出能够允许过来刻印光盘的人,问最少要给几个人光盘能让将所有人都刻印到。
N≤200
题解:
直接做强连通分量,然后将所有相邻的不同的强连通分量给做标记,弄成同一个集合,然后最后统计各个强连通分量的能到达数,为0则无人帮助则ans++。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 205
using namespace std;
int next[N*N],to[N*N],a[N],ls[N],dfn[N],low[N],c[N],rp[N],ru[N];
int n,x,ty,tot,num,cnt,ans;
void add(int u,int v)
{
next[++num]=ls[u];
to[num]=v;
ls[u]=num;
}
void tarjan(int dep)
{
dfn[dep]=low[dep]=++ty;
a[++tot]=dep;
c[dep]=1;
int i=ls[dep];
while (i)
{
if (!dfn[to[i]])
{
tarjan(to[i]);
low[dep]=min(low[dep],low[to[i]]);
}
else if (c[to[i]]) low[dep]=min(low[dep],dfn[to[i]]);
i=next[i];
}
if (dfn[dep]==low[dep])
{
cnt++;
int x=0;
while (x!=dep)
{
x=a[tot];
rp[x]=cnt;
c[x]=0;
tot--;
}
}
}
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; i++)
{
scanf("%d",&x);
while (x)
{
if(!x) break;
add(i,x);
scanf("%d",&x);
}
}
for (int i=1; i<=n; i++)
if (!dfn[i]) tarjan(i);
for (int i=1; i<=n; i++)
{
int j=ls[i];
while (j)
{
if (rp[i]!=rp[to[j]]) ru[rp[to[j]]]++;
j=next[j];
}
}
for(int i=1; i<=cnt; i++)
if (!ru[i]) ans++;
printf("%d\n",ans);
return 0;
}