题目大意:有光盘可以传着看,问最少从哪几个人分发,能全部传一遍。
题解:缩点后求入度为0的点的个数
代码:
#include<iostream> #include<cstdio> #include<cstring> #define maxn 22000 using namespace std; int n,sumedge,sumclr,top,tim,ans; int Stack[maxn],instack[maxn],low[maxn],dfn[maxn],bel[maxn],rd[maxn],head[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void Tarjian(int x){ Stack[++top]=x;instack[x]=true; low[x]=dfn[x]=++tim; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(instack[v])low[x]=min(low[x],dfn[v]); else if(!dfn[v]){ Tarjian(v); low[x]=min(low[x],low[v]); } } if(low[x]==dfn[x]){ sumclr++; while(Stack[top+1]!=x){ bel[Stack[top]]=sumclr; instack[Stack[top]]=false; top--; } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int x; while(1){ scanf("%d",&x); if(!x)break; add(i,x); } } for(int i=1;i<=n;i++)if(!dfn[i])Tarjian(i); for(int x=1;x<=n;x++){ for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(bel[x]!=bel[v])rd[bel[v]]++; } } for(int i=1;i<=sumclr;i++)if(!rd[i])ans++; printf("%d ",ans); return 0; }