题目传送门
题意解析:其实就是题目意思,找出一个被所有奶牛认为是最受欢迎的奶牛,并且这种认为是具有传递性的,最后找出有多少只最受欢迎的奶牛。
My opinion:看到题目的时候感觉跟并查集很像,但是一想,一只奶牛可以不止认为另一只奶牛是受欢迎的,所以并查集直接被排除了。然后就马上想到了图论,可以在每一个关系中建立一条由奶牛指向被认为是受欢迎的奶牛。那么可能会存在环,环中的每一只奶牛都认为对方是受欢迎的。先考虑没有环的情况,很明显,如果一只奶牛认为另一只奶牛是受欢迎的,那么它就一定不是最受欢迎的奶牛,因为它认为受欢迎的奶牛不认为它是受欢迎的,那么形成了一个DAG图,所以最后出度为0的奶牛就是最受欢迎的奶牛,当然前提是没有多个连通块,因为有多个联通块的话,就一定没有奶牛会被所有得奶牛认为是受欢迎的。现在考虑有环的情况就很简单了,我们把环看成一个点就行了(就是缩个点就好了)。
总结:
1、建图。
2、缩点。
3、判断是否是多个连通块。
4、找出出度为0的点。
不要问我为什么是c++。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define sqr(x) (x)*(x)
#define ll long long
#define db double
#define INF 200000000000000LL
#define eps 1e-8
using namespace std;
ll read(){
ll x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=10005,maxm=50005;
int n,m,len,num,top,Time;
int vet[maxm],Next[maxm],head[maxn];
int dfn[maxn],low[maxn],c[maxn],q[maxn];
int sum[maxn],edge[maxn];
void add(int u,int v){
vet[++len]=v;
Next[len]=head[u];
head[u]=len;
}
void dfs(int u){
dfn[u]=low[u]=++Time;
q[++top]=u;
for (int e=head[u];e;e=Next[e]){
int v=vet[e];
if (!dfn[v]){
dfs(v);
low[u]=min(low[v],low[u]);
}else low[u]=min(dfn[v],low[u]);
}
if (dfn[u]==low[u]){
num++;
while (top&&q[top]!=u)
c[q[top--]]=num;
c[u]=num;
top--;
}
}
int main(){
n=read(),m=read();
rep(i,1,m){
int u=read(),v=read();
add(u,v);
}
num=top=0;
rep(i,1,n)
if (!dfn[i]) dfs(i);
rep(i,1,n)
sum[c[i]]++;
rep(u,1,n)
for (int e=head[u];e;e=Next[e]){
int v=vet[e];
if (c[u]!=c[v])
edge[c[u]]++;
}
int ans=0,res=-1;
rep(i,1,num)
if (edge[i]==0){
ans++;
res=i;
}
if (ans==1) printf("%d\n",sum[res]);
else puts("0");
return 0;
}
附上AC记录:
我翻译成c++的
我翻译成c++的
我翻译成c++的
(重要的事情说三遍)
好早以前写p的,最近这题又拉出来做了一遍。