P2341
[USACO03FALL / HAOI2006] 受欢迎的牛 G
题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 \(A\) 喜欢 \(B\),\(B\) 喜欢 \(C\),那么 \(A\) 也喜欢 \(C\)。牛栏里共有 \(N\) 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。
输入格式
第一行:两个用空格分开的整数:\(N\) 和 \(M\)。
接下来 \(M\) 行:每行两个用空格分开的整数:\(A\) 和 \(B\),表示 \(A\) 喜欢 \(B\)。
输出格式
一行单独一个整数,表示明星奶牛的数量。
样例 #1
样例输入 #1
3 3
1 2
2 1
2 3
样例输出 #1
1
提示
只有 \(3\) 号奶牛可以做明星。
【数据范围】
对于 \(10\%\) 的数据,\(N\le20\),\(M\le50\)。
对于 \(30\%\) 的数据,\(N\le10^3\),\(M\le2\times 10^4\)。
对于 \(70\%\) 的数据,\(N\le5\times 10^3\),\(M\le5\times 10^4\)。
对于 \(100\%\) 的数据,\(1\le N\le10^4\),\(1\le M\le5\times 10^4\)。
对于一个环内的点可以缩点
tarjan完过后建新图
统计出度!!! out[i]
因为缩点过后新图为 DAG 所以最后的"点"(只有入度没有出度)即为答案
最后 若 out[i]==0 则 ans=num[i] (i所属强连通分量内点的个数)
若有 >1个 out[i]==0 则 没有明星 因为这些牛之间无法互相喜欢
不能统计入度 in[i]==tot-1 因为其它scc不一定要与ansのscc直接相连 可以间接传递!!! 所以统计出度才是正解!
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e4+5;
int n,m;
struct Graph{
int nxt,to,from;
}edge[N<<1];
int head[N],cnt;
inline void add(int u,int v)
{
cnt++;
edge[cnt].to=v;
edge[cnt].from=u;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
int dfn[N],low[N],times,stack_[N],pt,vis[N],num[N],belong[N],tot;
void tarjan(int x)
{
dfn[x]=low[x]=++times;
stack_[++pt]=x;
vis[x]=1;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[x]=min(low[x],low[v]);
}
else{
if(vis[v])
low[x]=min(low[x],dfn[v]);
}
}
if(dfn[x]==low[x])
{
tot++;
while(1)
{
belong[stack_[pt]]=tot;
vis[stack_[pt]]=0;
num[tot]+=1;
pt--;
if(stack_[pt+1]==x)break;
}
}
}
int out[N];
vector<int>cb[N];
vector<int>rdr[N];
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=cnt;i++)
{
if(belong[edge[i].from]!=belong[edge[i].to])
{
int x=belong[edge[i].from];
int y=belong[edge[i].to];
out[x]++;
cb[x].push_back(y);
rdr[y].push_back(x);
}
}
int pd=0,ans;
for(int i=1;i<=tot;i++)
if(!out[i])
ans=num[i],pd++;
if(pd>1)cout<<0<<"\n";
else cout<<ans<<"\n";
return 0;
}