PKU2186 Popular Cows 受欢迎的牛
Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N(N<=10000)头牛,给你M(M<=50000)对整数(A,B),表示牛A认为牛B受欢迎。这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。
接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复)
N<=10000,M<=50000
接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复)
N<=10000,M<=50000
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
思路
这是一道关于强连通的题,首先建好强连通分量;
再统计每个强连通的出度,如果有一个强连通出度为0;
则,这个强连通没有可以到达其它强连通的有向边;
也同时说明,这个强连通内的牛只互相喜欢,没有喜欢其它的牛;
但是不能有多个强连通分量出度为0;要保证它是被所有的牛喜欢的;
这样就算出,唯一出度为0的强连通分量里有多少头牛就可以了;
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n,m,ans,sum,s,top,num; ll head[100001],low[50001],dfn[50001]; ll f[50001],aa[50001],cd[50001],anss[50001]; struct sbbbbbbb { ll to,stb;//to为这条边到达的点,stb为上条边的编号 }a[100001]; inline void insert(ll x,ll y) { s++; a[s].to=y; a[s].stb=head[x]; head[x]=s; }//前向星连边 inline void dfs(ll x) { num++; dfn[x]=low[x]=num; top++; aa[top]=x; for(ll i=head[x];i;i=a[i].stb)//基础的遍历求low,和dfn的值 { ll xx=a[i].to; if(!dfn[xx]) { dfs(xx); low[x]=min(low[x],low[xx]); } else if(!f[xx]) low[x]=min(low[x],dfn[xx]); } if(low[x]==dfn[x])//如果可以通过返祖边回答父节点, //那么这些点都属于一个强连通分量 { sum++; f[x]=sum;//标记属于哪个强连通 while(aa[top]!=x) { f[aa[top]]=sum;//标记属于哪个强连通 anss[sum]++;//计算这个强连通分量里有多少个点 top--; } anss[sum]++; top--; } } int main() { n=read();m=read(); for(ll i=1;i<=m;i++) { ll x,y; x=read();y=read(); insert(x,y);//连边 } for(ll i=1;i<=n;i++) if(!dfn[i]) dfs(i); for(ll i=1;i<=n;i++) for(ll j=head[i];j;j=a[j].stb) if(f[i]!=f[a[j].to])//如果他们不是在一个强连通分量, //并且可以由f[i]到达f[a[j].to] cd[f[i]]++;//统计f[i]这个强连通的出度 for(ll i=1;i<=sum;i++) if(!cd[i])//枚举,看是否有出度为0的强连通 { if(ans==0) ans=anss[i]; else//有多个出度为0,则没有答案 { printf("0"); return 0; } } printf("%lld",ans); }
下面纯属搞笑,可以不理会:
黄牛模板:
#include<bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n,m,ans,sum,s,top,num; ll head[100001],low[50001],dfn[50001]; ll f[50001],aa[50001],cd[50001],anss[50001]; struct sbbbbbbb { ll to,stb; }a[100001]; inline void insert(ll x,ll y) { s++; a[s].to=y; a[s].stb=head[x]; head[x]=s; } inline void dfs(ll x) { num++; dfn[x]=low[x]=num; top++; aa[top]=x; for(ll i=head[x];i;i=a[i].stb) { ll xx=a[i].to; if(!dfn[xx]) { dfs(xx); low[x]=min(low[x],low[xx]); } else if(!f[xx]) low[x]=min(low[x],dfn[xx]); } if(low[x]==dfn[x]) { sum++; f[x]=sum; while(aa[top]!=x) { f[aa[top]]=sum; anss[sum]++; top--; } anss[sum]++; top--; } } int main() { n=read();m=read(); for(ll i=1;i<=m;i++) { ll x,y; x=read();y=read(); insert(x,y); }//输入牛的编号 for(ll i=1;i<=n;i++) if(!dfn[i]) dfs(i);//找谁是最受欢迎的牛 printf("最 受 欢 迎 的 牛 是 黄 牛\n我 是 黄 牛 沃 泰 牛"); }
只要将黄牛模板交到入门oj的4916
就会AC