再也不水题了!!!
这周集训,本来是周一直到周日的,这不台风来了,于是放了两天假,也刚好让我这个蒟蒻填填坑。。。
言归正传,P2341 [HAOI2006]受欢迎的牛
精简题意,把A喜欢B看作是A向B建一条边,则一个强连通子图内的所有奶牛都是互相喜欢的,Tarjan缩点后就成了一个有向无环图,因为明星是要被所有奶牛喜欢的,所以所有点都能到达的点上的所有奶牛都是明星。
因为是个有向无环图,所以如果只有一个出度为零的点,那么这个点的奶牛数即为答案。
反之,如果有多个出度为零的点,那么任何点一定不能被所有点到达。于是就成了一道水题。
AC代码:
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0')c=getchar();
while(c>='0')x=x*10+c-'0',c=getchar();
return x;
}
const int maxn=1e4+5;
int tim,cd[maxn],dfn[maxn],low[maxn],cnt,st[maxn],bein[maxn],belong[maxn],size[maxn],scc_cnt;
int n,m;vector<int>e[maxn];
void Tarjan(int x){
dfn[x]=low[x]=++tim;
st[++cnt]=x;bein[x]=true;
for(int i=0;i<e[x].size();i++){
int to=e[x][i];
if(!dfn[to])Tarjan(to),low[x]=min(low[x],low[to]);
else if(bein[to])low[x]=min(low[x],dfn[to]);
}
if(dfn[x]==low[x]){
scc_cnt++;int k;
do{
k=st[cnt--];
belong[k]=scc_cnt;
bein[k]=false;
size[scc_cnt]++;
}while(k^x);
}
}
int main(){
n=read(),m=read();
for(int i=0;i<m;i++){
int x=read(),y=read();
e[x].push_back(y);
}
for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
int ans=0;bool flag=true;
for(int i=1;i<=n;i++){
for(int j=0;j<e[i].size();j++){
if(belong[i]!=belong[e[i][j]])
cd[belong[i]]++;
}
}
for(int i=1;i<=scc_cnt;i++){
if(cd[i]==0){
if(flag){
ans=size[i];flag=false;
}
else{
puts("0");return 0;
}
}
}
printf("%d",ans);
return 0;
}
P.S. 我居然一遍AC了,不敢相信!!!