题目链接:http://poj.org/problem?id=2186
题意:
有一群绵羊,
现在有一些喜欢关系,喜欢关系是可以传递的。
问有多少绵羊直接或间接地被所有绵羊喜欢。
算法:
首先求强联通并缩点,方法见BYVoid的《有向图强连通分量的Tarjan算法》。
缩点之后形成了一个DAG。
现在来看一下有几个出度为0的块。
如果没有出度为0的块,
必然无解。
因为某个块有指向另一个块的边的话,那么那个块肯定就没有指向它的边或有向路径了,因为那样就形成了环。
如果出度为0的块多于一个,也无解。
因为显然从一个出度为零的块无法到达另一个出度为零的块。
如果有且只有一个出度为0的块,
这个块中的点即为解。
代码如下:
#include<cstdio> #include<cstring> #include<vector> #include<stack> using namespace std; const int MAXN=11000; int tot,blkn; int low[MAXN],dfsn[MAXN],blk[MAXN]; bool ins[MAXN],dex[MAXN]; vector<int>map[MAXN]; vector<int>blk_map[MAXN]; stack<int>ss; void dfs(int u) { dfsn[u]=tot++; ins[u]=true; low[u]=dfsn[u]; ss.push(u); for(int i=0; i<map[u].size(); i++) { int v=map[u][i]; if(dfsn[v]!=-1) { if(ins[v]) { low[u]=min(low[u],dfsn[v]); } } else { dfs(v); low[u]=min(low[u],low[v]); } } if(dfsn[u]!=low[u]) return; blkn++; while(!ss.empty()) { int v=ss.top(); ss.pop(); ins[v]=false; blk[v]=blkn; if(v==u)break; } return; } void blk_dfs(int u) { dfsn[u]=1; for(int i=0; i<blk_map[u].size(); i++) { if(!dfsn[blk_map[u][i]]) blk_dfs(blk_map[u][i]); } return; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=0; i<n; i++) { map[i].clear(); blk_map[i].clear(); } memset(ins,0,sizeof(ins)); memset(dex,0,sizeof(dex)); memset(blk,-1,sizeof(blk)); memset(dfsn,-1,sizeof(dfsn)); while(!ss.empty()) ss.pop(); while(m--) { int u,v; scanf("%d%d",&u,&v); if(u==v) continue; u--; v--; map[v].push_back(u); } blkn=0; for(int i=0; i<n; i++) if(blk[i]==-1) { tot=0; dfs(i); } for(int i=0; i<n; i++) { for(int j=0; j<map[i].size(); j++) { int v=map[i][j]; if(blk[i]==blk[v])continue; blk_map[blk[i]].push_back(blk[v]); dex[blk[v]]=true; } } int rt,cot=0; for(int i=1; i<=blkn; i++) { if(!dex[i]) { rt=i; cot++; } } if(cot>1) { puts("0"); continue; } memset(dfsn,0,sizeof(dfsn)); blk_dfs(rt); { int i; for(i=1; i<=blkn; i++) { if(!dfsn[i])break; } if(i<=blkn) { puts("0"); continue; } } int ans=0; for(int i=0; i<n; i++) { if(blk[i]==rt) { ans++; } } printf("%d\n",ans); } return 0; }