洛谷P2835 刻录光盘

时间:2021-07-18 00:20:15

传送门

题目大意:有光盘可以传着看,问最少从哪几个人分发,能全部传一遍。

题解:缩点后求入度为0的点的个数

代码:

洛谷P2835 刻录光盘洛谷P2835 刻录光盘
#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\n",ans);
return 0;
}
AC