pku 2186(强连通分量)

参考:http://www.cppblog.com/Darren/archive/2008/12/05/68682.html

算法证明:http://www.cppblog.com/RyanWang/archive/2009/02/26/74984.aspx

求一次强连通分量,然后将每个分量看作一个点,找一个唯一的出度为0的点,其分量内包含的点的数量即为结果。

 

#include <iostream> #include <cstring> using namespace std; const int MAXN=10005; class node { public: int v; node *next; }; node edge[MAXN],edge_reve[MAXN],Index[MAXN*15]; bool visit[MAXN]; int DFN[MAXN],belong[MAXN],in[MAXN],size[MAXN],pos,cnt,numv,deep; //numv为点的个数,pos为索引表的下标,cnt为连通分量计数器,deep计算迭代深度,即表示每个分量所包含的点的个数 //DFN为时间戳,belong记录每个点属于哪个分量,in记录出度 void add_edge(int u,int v) //构造邻接表和反向表 { node* ptr=&Index[pos++]; ptr->v=v; ptr->next=edge[u].next; edge[u].next=ptr; node* ptr_re=&Index[pos++]; ptr_re->v=u; ptr_re->next=edge_reve[v].next; edge_reve[v].next=ptr_re; } void DFS(int x) { visit[x]=true; for(node* i=edge[x].next;i!=NULL;i=i->next) { if(!visit[i->v]) DFS(i->v); } DFN[cnt++]=x; } void DFS_reve(int x) { visit[x]=true; for(node *ptr=edge_reve[x].next;ptr!=NULL;ptr=ptr->next) { if(!visit[ptr->v]) { deep++; DFS_reve(ptr->v); } } belong[x]=cnt; } void degree() //统计出度 { node *ptr; memset(in,0,sizeof(in)); for(int i=1;i<=numv;++i) { for(ptr=edge[i].next;ptr!=NULL;ptr=ptr->next) if(belong[i]!=belong[ptr->v]) in[belong[i]]++; } int count=0,tag; for(int i=0;i<cnt;++i) if(in[i]==0) { tag=i; count++; } if(count!=1) cout<<0<<endl; else cout<<size[tag]<<endl; } int main() { int n,u,v; cin>>numv>>n; pos=0; memset(visit,false,sizeof(visit)); cnt=0; for(int i=0;i<n;++i) { cin>>u>>v; add_edge(u,v); } for(int i=1;i<=numv;++i) { if(!visit[i]) DFS(i); }; memset(visit,false,sizeof(visit)); cnt=0; for(int i=numv-1;i>=0;--i) { if(!visit[DFN[i]]) { deep=1; DFS_reve(DFN[i]); size[cnt]=deep; //记录每个连通分量所包含的点的个数 cnt++; } } degree(); return 0; }

 

 

 

tarjan实现版本

 

#include <iostream> #include <cstring> using namespace std; const int MAXN=10005; class node { public: int v; node *next; }; node edge[MAXN],Index[MAXN*8]; bool instack[MAXN]; int my_stack[MAXN*5],step; //step用来记录栈中元素个数 int DFN[MAXN],belong[MAXN],in[MAXN],size[MAXN],low[MAXN],pos,cnt,numv,visitNum,deep; //numv为点的个数,pos为索引表的下标,cnt为连通分量计数器,deep计算迭代深度,即表示每个分量所包含的点的个数 //DFN为时间戳,belong记录每个点属于哪个分量,in记录出度 void add_edge(int u,int v) //构造邻接表 { node* ptr=&Index[pos++]; ptr->v=v; ptr->next=edge[u].next; edge[u].next=ptr; } void tarjan(int x) { int tag; DFN[x]=++visitNum; low[x]=visitNum; instack[x]=true; my_stack[++step]=x; for(node *ptr=edge[x].next;ptr!=NULL;ptr=ptr->next) { tag=ptr->v; if(!DFN[tag]) { tarjan(tag); if(low[tag]<low[x]) low[x]=low[tag]; } else if(instack[tag] && DFN[tag] < low[x]) low[x]=DFN[tag]; } if(DFN[x]==low[x]) { cnt++; deep=0; do { tag=my_stack[step--]; instack[tag]=false; belong[tag]=cnt; deep++; } while(tag!=x) ; size[cnt]=deep; } } void solve() { step=0; cnt=0; visitNum=0; memset(DFN,0,sizeof(DFN)); memset(instack,false,sizeof(instack)); memset(low,0,sizeof(low)); for(int i=1;i<=numv;++i) if(!DFN[i]) tarjan(i); } void degree() //统计出度 { node *ptr; memset(in,0,sizeof(in)); for(int i=1;i<=numv;++i) { for(ptr=edge[i].next;ptr!=NULL;ptr=ptr->next) if(belong[i]!=belong[ptr->v]) in[belong[i]]++; } int count=0,tag=0; for(int i=1;i<=cnt;++i) if(in[i]==0) { tag=i; count++; } if(count!=1) cout<<0<<endl; else cout<<size[tag]<<endl; } int main() { int n,u,v; cin>>numv>>n; pos=0; for(int i=0;i<n;++i) { cin>>u>>v; add_edge(u,v); } solve(); degree(); return 0; }

你可能感兴趣的:(算法,Class)