POJ 1236

先Tarjan缩点,第一问,只要给所有入度为0的点发放就行了,第二问,可以证明当一个有向图中所有的点的入度和出度都不为零时,这个有向图一定是强联通图,否则一定不是,所以统计下入度0的点和出度为0的点的个数,然后输出它们的最大值即可。ps:1的时候要特判

#include<cstdio>
#include<iostream>
#define N 11000
using namespace std;
int to[N*10],cnt,nxt[N*10],head[N],vis[N],low[N],dfn[N],now;
int z[N],top,n,m,in[N],r[N],c[N],rr,cc,cl,col[N],t[200][200];
void add(int x,int y){
to[++cnt]=y;
nxt[cnt]=head[x];
head[x]=cnt;
}
void dfs(int x){
vis[x]=1;dfn[x]=low[x]=++now;
z[++top]=x;in[x]=1;
for(int i=head[x];i;i=nxt[i]){
if(vis[to[i]]){
if(in[to[i]]) low[x]=min(low[x],dfn[to[i]]);
}else {
dfs(to[i]);
low[x]=min(low[x],low[to[i]]);
}
}
if(low[x]==dfn[x]){
col[x]=++cl;
while(z[top]!=x)in[z[top]]=0,col[z[top]]=cl,top--;
in[x]=0,top--;
}
}
int main(){
int x;
scanf("%d",&n);
for(int i=1;i<=n;i++)while(scanf("%d",&x)&&x!=0) add(i,x);
for(int i=1;i<=n;i++) if(!vis[i])
dfs(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=nxt[j]) if(col[i]!=col[to[j]]&&!t[col[i]][col[to[j]]])
t[col[i]][col[to[j]]]=1,r[col[to[j]]]++,c[col[i]]++;
for(int i=1;i<=cl;i++) rr+=r[i]==0,cc+=c[i]==0;
printf("%d %d",rr,cl==1?0:max(rr,cc));
}

原文地址:https://www.cnblogs.com/blogoflyn/p/10849916.html