POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】

来源:互联网 发布:字符串压缩 java 编辑:程序博客网 时间:2024/05/17 05:07
/*Popular Cows ( POJ No.2186)每头牛都想成为牛群中的红人。给定 N 头牛的牛群和 M 个有序对(A, B)。 (A, B)表示牛 A 认为牛 B 是红人。该关系具有传递性,所以如果牛 A 认为牛 B 是红人,牛 B 认为牛 C 是红人,那么牛 A 也认为牛 C 是红人。不过,给定的有序对中可能包含(A, B)和(B, C),但不包含(A, C)。求被其他所有牛认为是红人的牛的总数。限制条件 1 ≤ N ≤ 10000 1 ≤ M ≤ 50000 1 ≤ A, B ≤ N Sample Input3 31 22 12 3Sample Output1次题为典型的求强连通分量的题目,将强连通分量缩点并得到DAG,求的出度为0的强连通分量的点的个数就是答案*/ 
//Kosaraju算法,异常巧妙#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int maxn=10000+10,maxm=50000+10;int n,m,scc;int stack[maxn],top;int head1[maxn],head2[maxn];struct node{int to,next;};node edge1[maxm],edge2[maxm];//正向边与反向边bool vis[maxn];int num[maxn];//强连通分量点个数 void dfs1(int u){int v;for(int i=head1[u];i!=-1;i=edge1[i].next){v=edge1[i].to;if(!vis[v]){vis[v]=1;dfs1(v);}}stack[top++]=u;}void dfs2(int u){int v;num[scc]++;for(int i=head2[u];i!=-1;i=edge2[i].next){v=edge2[i].to;if(!vis[v]){vis[v]=1;dfs2(v);}}}int main(int argc,char* argv[]){int u,v;while(~scanf("%d%d",&n,&m)){//initscc=top=0;memset(head1,-1,sizeof(head1));memset(head2,-1,sizeof(head2));for(int i=0;i<m;i++){scanf("%d%d",&u,&v);edge1[i].to=v;edge1[i].next=head1[u];head1[u]=i;edge2[i].to=u;edge2[i].next=head2[v];head2[v]=i;}memset(vis,0,sizeof(vis));for(int i=1;i<=n;i++)if(!vis[i]){vis[i]=1;dfs1(i);}int root;memset(vis,0,sizeof(vis));for(top--;top>=0;top--)if(!vis[stack[top]]){root=stack[top];scc++;vis[stack[top]]=1;dfs2(stack[top]);}memset(vis,0,sizeof(vis));vis[root]=1;int ans=num[scc];//如果是个连通图,则从根结点可以一次遍历完dfs2(root);for(int i=1;i<=n;i++)if(!vis[i]){ans=0;break;}printf("%d\n",ans);}return 0;}


//tarjan算法求强连通分量,然后求出出度为0的强连通分量的点的个数 #include<cstdio>#include<iostream>#include<cstring>using namespace std;const int maxn=10000+10,maxm=50000+10;int head[maxn];struct node{int to,next;}edge[maxm];int n,m;int num[maxn],scc;//num为强连通中点的个数,sc为强连通分量的个数int dfn[maxn],low[maxn],index;int stack[maxn],top;bool is[maxn];//判断是否在栈中 bool out[maxn];//记录出度 int belong[maxn];//记录点在哪个强连通分量中 void tarjan(int u){int v;dfn[u]=low[u]=++index;stack[top++]=u;is[u]=true;for(int i=head[u];i!=-1;i=edge[i].next){v=edge[i].to;if(!dfn[v]){tarjan(v);if(low[u]>low[v]) low[u]=low[v];}else if(is[v]&&low[u]>dfn[v])low[u]=dfn[v];}if(dfn[u]==low[u]){scc++;do{v=stack[--top];belong[v]=scc;num[scc]++;is[v]=false;}while(u!=v);}}int main(){int u,v;while(~scanf("%d%d",&n,&m)){//initmemset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(num,0,sizeof(num));//memset(belong,0,sizeof(belong));scc=index=top=0;memset(head,-1,sizeof(head));for(int i=0;i<m;i++){//建图 scanf("%d%d",&u,&v);edge[i].next=head[u];head[u]=i;edge[i].to=v;}for(int i=1;i<=n;i++)if(!dfn[i]){tarjan(i);}memset(out,0,sizeof(out));for(int i=1;i<=n;i++)if(!out[belong[i]]){for(int j=head[i];j!=-1;j=edge[j].next){int v=edge[j].to;if(belong[i]!=belong[v]){out[belong[i]]=true;break;}}}int cnt=0,ans;for(int i=1;i<=scc;i++)if(!out[i]){cnt++;ans=num[i];}if(cnt>1) ans=0;printf("%d\n",ans);}return 0;}


还有个Garbow算法也是求强连通分量的
1 0
原创粉丝点击