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\)。
这道题就像将在处于一强连通分量的点揉成一个点,如果各个连通分量可以首尾相连形成一个长串,那么串上最后一个强连通分量团里奶牛的个数就是答案,答案是统计出度为零的团,我灵机一动改成了出度不为零,但错了,因为有的团出度和入度都不为零,我写博客时又想到如果缩点之后有两个互相独立的团怎么办,但很快我就想通了,如果有两个独立的团,就有两个团的出度为零,因为强连通分量视为没有出度,这时候就会被特判掉,为什么出度为零的点在两个或以上就不行呢,因为如果有两个说明这两个团只能有其他团到达,但从一个团是不可能同时到达这两个团的
#include<iostream>
#include<vector>
#include<stack>
#define int long long
using namespace std;
const int N=1e5+5;
int n,m,a,b,cnt=0,t=0,ans=0,num=0;
int low[N],dfsn[N],vis[N],scc[N],sz[N],inc[N],outc[N];
vector<int>v[N];
stack<int>s;
void dfs(int x){low[x]=dfsn[x]=++t;vis[x]=1,s.push(x);for(int y:v[x]){if(!dfsn[y]){dfs(y);low[x]=min(low[x],low[y]);}else if(vis[y])low[x]=min(low[x],dfsn[y]);}if(low[x]==dfsn[x]){cnt++;while(s.top()!=x){vis[s.top()]=0;scc[s.top()]=cnt;sz[cnt]++;s.pop();}vis[s.top()]=0;scc[s.top()]=cnt;sz[cnt]++;s.pop();}}
signed main(){cin>>n>>m;while(m--){cin>>a>>b;v[a].push_back(b);}for(int i=1;i<=n;i++)if(!dfsn[i])dfs(i);for(int x=1;x<=n;x++){for(int y:v[x]){if(scc[x]!=scc[y]){inc[scc[y]]++;outc[scc[x]]++;}}}for(int i=1;i<=cnt;i++){if(!outc[i]){ans+=sz[i];num++;}}if(num>1)cout<<0;else cout<<ans;return 0;
}