poj2186Popular Cows+tarjan缩点+建图
题意:
给出m条关系,表示n个牛中的崇拜关系,这些关系满足传递性。问被所有牛崇拜的牛有几头;
思路:
先利用tarjan缩点,同一个点中的牛肯定就是等价的了,建立新的图,找出其中出度为0的点。如果这个点唯一,那么答案就是这个缩点中包含的所有点。
如果不唯一,那么答案不存在。因为有两个点出度为0,说明这两个点相互不羡慕,0。如果没有出度为0的点,说明缩点有问题;
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <vector> #include <map> #include <set> #include <queue> #include <stack> #include <list> #include <iterator> using namespace std; const int maxn = 10009; int n,m,dfn[maxn],low[maxn],vis[maxn],belong[maxn],tot,scc; int num[maxn]; stack<int>s; vector<int>mp[maxn]; vector<int>nn[maxn]; void init(){ memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(belong,0,sizeof(belong)); memset(num,0,sizeof(num)); tot = 0; scc = 0; for(int i=1; i<=n; i++) mp[i].clear(),nn[i].clear(); while(!s.empty())s.pop(); } void tarjan(int x) { dfn[x] = low[x] = ++tot; s.push(x);vis[x] = 1; for(int i=0; i<mp[x].size(); i++) { int v = mp[x][i]; if(!dfn[v]) { tarjan(v); low[x] = min(low[v],low[x]); } else if(vis[v]) { low[x] = min(low[x],dfn[v]); } } if(low[x] == dfn[x]) { scc++; while(1) { int o = s.top(); s.pop(); vis[o] = 0; belong[o] = scc; num[scc]++; if(o==x)break; } } } void solve() { for(int i=1; i<=n; i++) { for(int j=0;j<mp[i].size();j++) { int v = mp[i][j]; if(belong[v]!=belong[i]) { nn[belong[i]].pb(belong[v]); } } } int cnt = 0,ans; for(int i=1; i<=scc; i++) { if(nn[i].size()==0) { cnt++; ans = i; } } if(cnt==1) { printf("%d\n",num[ans]); } else printf("0\n"); } int main(){ while(~scanf("%d%d", &n, &m)) { init(); for(int i=1; i<=m; i++) { int u,v; scanf("%d%d", &u, &v); mp[u].pb(v); } for(int i=1; i<=n; i++) { if(dfn[i]==0)tarjan(i); } solve(); } return 0; }
skr