题目描述
P2341 [USACO03FALL][HAOI2006]受欢迎的牛 G
解法:
首先,明确一下什么是明星奶牛:受欢迎的牛只可能是图中唯一的出度为0的强连通分量中的所有奶牛。
为什么?
强连通分量中,所有的结点都可以相互达到,也就是说强联通分量中的所有奶牛都相互喜欢。出度不为0的话,则强连通分量中的奶牛并不一定满足被所有奶牛喜欢的条件(当然,一个结点也算是某一个强联通分量,若该结点出度为0,也是一头明星奶牛)
若出现两个及两个以上出度为0的强连通分量,这两块是独立,换句话时候也就是第一分量的所有奶牛并不喜欢第二分量的任何一头奶牛,同理可推第二分量,所以这些独立的强连通分量中的奶牛都不是明星奶牛
#include <bits/stdc++.h>
using namespace std;int n, m, a, b, t, cnt, cont, ans;
int v[100010], nex[100010]
int fst[10010], fn[10010], low[10010], scc[10010], ssize[10010], out[10010];
bool f[10010];
stack<int> s;void tarjan(int k){
low[k] = dfn[k] = ++t;f[k] = true;s.push(k);for(int i=fst[k];i!=-1;i=nex[i]){
if(!dfn[v[i]]){
tarjan(v[i]);low[k] = min(low[k],low[v[i]]);}else{
if(f[v[i]])low[k] = min(low[k], dfn[v[i]]);}}if(low[k]==dfn[k]){
f[k] = false;scc[k] = ++cnt; // cnt记录强连通分量个数,ssc表示k在第cnt个强联通分中ssize[cnt] = 1; // ssize记录第cnt个强联通分量的成员数while(s.top()!=k){
scc[s.top()] = cnt;f[s.top()] = false;ssize[cnt]++;s.pop();}s.pop();}return;
}int main()
{
cin >> n >> m;memset(fst, -1, sizeof(fst));memset(low, 0x7f, sizeof(low));for(int i=1;i<=m;i++){
scanf("%d%d", &a, &b);nex[i] = fst[a];v[i]= b;fst[a] = i;}for(int i=1;i<=n;i++){
if(!dfn[i]){
t = 0;tarjan(i);}}for(int i=1;i<=n;i++){
for(int j=fst[i];j!=-1;j=nex[j]){
if(scc[i]!=scc[v[j]]) // 如果i和其邻接点不再一个连通分量,则该连通分量有一个出度out[scc[i]]++;}}// 记录出度为0的强联通分量for(int i=1;i<=cnt;i++){
if(out[i]==0){
cont++;ans += ssize[i];}}if(cont==1)cout << ans;elsecout << 0;return 0;
}