题意:每头牛都想成为牛群中的红人,现在又N头牛和M个有序对(A,B)。(A,B)表示牛A认为牛B是红人。该关系具有传递性,所以如果A认为B是红人,B认为C是红人,则A认为C是红人。求被其他所有牛认为是红人的牛的总数。
思路:假设有两头牛A和B都被其他所有牛认为是红人。那么显然,A被B认为是红人,B也被A认为是红人,即存在一个包含A,B两个顶点的圈,或者说A,B属于同一个强联通分量。反之,如果一头牛被其他所有牛认为是红人,那么其所属的强联通分量内所有的牛都被其他所有牛认为是红人。由此,我们把图进行强联通分解后,至多有一个强联通分量满足题目的要求。
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <vector> using namespace std; const int maxn = 10010; int n,m; vector<int>g[maxn]; vector<int>rg[maxn]; vector<int>vs; bool used[maxn]; int cmp[maxn]; void add_edge(int from,int to) { g[from].push_back(to); rg[to].push_back(from); } void dfs(int v) { used[v] = true; for(int i = 0; i < g[v].size(); i++) { if(!used[g[v][i]]) dfs(g[v][i]); } vs.push_back(v); } void rdfs(int v,int k) { used[v] = true; cmp[v] = k; for(int i = 0; i < rg[v].size(); i++) { if(!used[rg[v][i]]) rdfs(rg[v][i],k); } } int scc() { memset(used,false,sizeof(used)); vs.clear(); for(int v = 1; v <= n; v++) { if(!used[v]) dfs(v); } memset(used,false,sizeof(used)); int k = 0; for(int i = vs.size()-1; i >= 0; i--) { if(!used[vs[i]]) rdfs(vs[i],k++); } return k; } int main() { cin >> n >> m; for(int i = 0; i < m; i++) { int u,v; cin >> u >> v; //u--,v--; add_edge(u,v); } int ans = scc(); int u = 0,num = 0; for(int v = 1; v <= n; v++) { if(cmp[v]==ans-1) { u = v; num++; } } memset(used,false,sizeof(used)); rdfs(u,0); for(int v = 1; v <= n; v++) { if(!used[v]) { num = 0; break; } } cout<<num<<endl; return 0; }