想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:题目大意是:在一个牧群中,有N个奶牛,给定M对关系(A,B)表示A仰慕B,而且仰慕关系有传递性,问被所有奶牛(除了自己)仰慕的奶牛个数
解题思路:找出所有的连通分量,如果只有一个连通分量的出度为0,那么输出那个连通分量的点的个数即可,如果不唯一就输出0
因为连通分量的出度有两个的话,那么肯定至少存在一头牛不仰慕另外一头牛,所以我们至少保证要出度为0的连通分量唯一
/*
tarjan
Memory 872K
Time 32MS
*/
#include <iostream>
using namespace std;
#define MAXM 50010
#define MAXV 10010
#define min(a,b) (a>b?b:a)
typedef struct{
int s,t,next;
}Edge;
Edge edge[MAXM];
int n,m,headlist[MAXV];
int dfn[MAXV]; //第一次访问的步数
int low[MAXV]; //子树中最早的步数
int stap[MAXV],stop; //模拟栈
bool instack[MAXV]; //是否在栈中
int count; //记录连通分量的个数
int cnt; //记录搜索步数
int belong[MAXV]; //属于哪个连通分量
void init(){
count=stop=cnt=0;
memset(instack,false,sizeof(instack));
memset(dfn,0,sizeof(dfn));
}
void tarjan(int x){
int i;
dfn[x]=low[x]=++cnt;
stap[stop++]=x;
instack[x]=true;
for(i=headlist[x];i!=-1;i=edge[i].next){
int a=edge[i].t;
if(!dfn[a]){
tarjan(a);
low[x]=min(low[a],low[x]);
}else if(instack[a])
low[x]=min(dfn[a],low[x]);
}
if(low[x]==dfn[x]){
count++;
while(1){
int tmp=stap[--stop];
belong[tmp]=count;
instack[tmp]=false;
if(tmp==x) break;
}
}
}
void work(){
init();
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
}
void output(){
int i,outdegree[MAXV]={0},outzero=0,ans=0;
for(i=0;i<m;i++){
if(belong[edge[i].s]!=belong[edge[i].t]){
outdegree[belong[edge[i].s]]++;
}
}
for(i=1;i<=count;i++){
if(!outdegree[i]){
outzero++;
cnt=i;
}
}
for(i=1;i<=n;i++)
if(belong[i]==cnt) ans++;
if(outzero==1) printf("%d\n",ans);
else printf("0\n");
}
int main(){
int i,a,b;
while(~scanf("%d%d",&n,&m)){
memset(headlist,-1,sizeof(headlist));
for(i=0;i<m;i++){
scanf("%d%d",&a,&b);
edge[i].s=a;
edge[i].t=b;
edge[i].next=headlist[a];
headlist[a]=i;
}
work();
output();
}
return 0;
}
=============================================================================
/*
kosaraju
Memory 1036K
Time 63MS
*/
#include <iostream>
using namespace std;
#define MAXM 50010
#define MAXV 10010
#define min(a,b) (a>b?b:a)
typedef struct{
int s,t,next,next2;
}Edge;
Edge edge[MAXM];
int n,m,headlist[MAXV],headlist2[MAXV];
int order[MAXV],belong[MAXV];
int num,count;
bool vis[MAXV];
void dfs(int x){
int i,a;
vis[x]=1;
for(i=headlist[x];i!=-1;i=edge[i].next){
a=edge[i].t;
if(!vis[a]) dfs(a);
}
order[++num]=x;
}
void dfst(int x){
int i,a;
belong[x]=count; //记录结点属于哪个连通分量
vis[x]=1;
for(i=headlist2[x];i!=-1;i=edge[i].next2){ //要将边反过来遍历一遍
a=edge[i].s;
if(!vis[a]) dfst(a);
}
}
void kosaraju(){
int i;
memset(vis,0,sizeof(vis));
num=count=0;
for(i=1;i<=n;i++)
if(!vis[i]) dfs(i);
memset(vis,0,sizeof(vis));
for(i=n;i>=1;i--)
if(!vis[order[i]]){
count++;
dfst(order[i]);
}
}
void output(){
int i,outdegree[MAXV]={0},outzero=0,ans=0,cnt;
for(i=0;i<m;i++){
if(belong[edge[i].s]!=belong[edge[i].t]){
outdegree[belong[edge[i].s]]++;
}
}
for(i=1;i<=count;i++){
if(!outdegree[i]){
outzero++;
cnt=i;
}
}
for(i=1;i<=n;i++)
if(belong[i]==cnt) ans++;
if(outzero==1) printf("%d\n",ans);
else printf("0\n");
}
int main(){
int i,a,b;
while(~scanf("%d%d",&n,&m)){
memset(headlist,-1,sizeof(headlist));
memset(headlist2,-1,sizeof(headlist2));
for(i=0;i<m;i++){
scanf("%d%d",&a,&b);
edge[i].s=a;
edge[i].t=b;
edge[i].next=headlist[a];
headlist[a]=i;
edge[i].next2=headlist2[b]; //记录反边
headlist2[b]=i;
}
kosaraju();
output();
}
return 0;
}