[BZOJ 1051] 受欢迎的牛
Link:
Solution:
因为每一个强连通块中的点具有等效性,可以统一处理
tarjan缩点建DAG
发现新图中仅在只有一个出度为1的点时才能出现符合要求的点,统计即可
(否则必然不可能有一个强连通分块是所有点的汇点)
Tips:为了建立新图可以不用储存边集数组,使用邻接表中的数据即可
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=10005; vector<int> G[MAXN]; stack<int> st; bool instack[MAXN]; int n,m,scc,T_stamp,col[MAXN],dfn[MAXN],low[MAXN],out[MAXN],cnt[MAXN]; void tarjan(int u) //Tarjan { dfn[u]=low[u]=++T_stamp; instack[u]=true;st.push(u); for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]); else if(instack[v]) low[u]=min(low[u],low[v]); } if(low[u]==dfn[u]) { scc++;int t=-1; while(t!=u) { t=st.top();st.pop(); col[t]=scc;cnt[scc]++; instack[t]=false; } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); G[x].push_back(y); } tarjan(1); for(int i=1;i<=n;i++) //统计 for(int j=0;j<G[i].size();j++) { int u=i,v=G[i][j]; if(col[u]!=col[v]) out[col[u]]++; } int t=0,sum=0; for(int i=1;i<=scc;i++) if(out[i]==0) t++,sum+=cnt[i]; if(t==1) printf("%d",sum); else printf("0"); return 0; }