
题意:
给出n头牛,m个关系,关系x,y表示牛x喜欢牛y,如果x喜欢y,y喜欢z,那么x也喜欢z。
是否存在一些牛,其他所有牛都喜欢他。
明显,如果是一个大的联通分量,那么他们相互喜欢,如果有几个联通分量,那么如果有两个或两个以上的联通分量没有指向其他联通分量,那么这样的牛是不存在的,如图:

所以我们出了计算联通分量,还要存放,某个联通分量有多少个牛组成,以及这个联通分量有没有出度,如果这样的牛存在,那么它所在的联通分量必然出度为0,并且只有1个出度为0的联通分量。
//POJ_2186_Popular Cows
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=1e5+6;
int sum[maxn],col[maxn],outdeg[maxn],sta[maxn];
int n,m,tim,cnt,Count,top,head[maxn],dfn[maxn],vis[maxn],low[maxn];
struct node
{
int to,nxt;
};
node edge[500005];
void init(){
memset(head,-1,sizeof(head));
tim=cnt=top=Count=0;
for(int i=0;i<=n;i++)
sum[i]=col[i]=outdeg[i]=sta[i]=dfn[i]=vis[i]=low[i]=0;
}
void add(int u,int v){
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
void tarjian(int u){
vis[u]=1;
dfn[u]=low[u]=tim++;
sta[++top]=u;
for(int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v]==0) tarjian(v);
if(vis[v]==1) low[u]=min(low[u],low[v]);
}
if(low[u]==dfn[u]){
Count++;
do{
col[sta[top]]=Count;//属于第几个联通分量
sum[Count]++;//该联通分量有几个节点
vis[sta[top]]=-1;
}while(sta[top--]!=u);//出栈
}
}
int main(){
while (scanf("%d%d",&n,&m)!=EOF)
{
int x,y;
init();
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++)
if(!vis[i]) tarjian(i);
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=edge[j].nxt){
int v=edge[j].to;
if(col[i]!=col[v]) //i与它指向的点不是同一个联通分量
outdeg[col[i]]++; //i所在的联通分量出度++
}
}
int ans = 0,flag=0;//利用flag 来标记是第几次出度为0;
for (int i = 1; i <=Count; i++)
{
if(flag && outdeg[i]==0){//如果falg =1 后,说明已经有了一个出度为0的,如果再有,ans=0;
ans=0;break;
}
if(!flag && outdeg[i]==0){//开始 flag =0 此时如果有出度为0的,那么ans有了
ans=sum[i];
flag=1;
}
}
printf("%d\n",ans);
}
return 0;
}
299



被折叠的 条评论
为什么被折叠?



