转载请注明:http://blog.csdn.net/idrandom/article/details/52064804
题目链接:http://poj.org/problem?id=2186
题意很简单,给你一个有向图,问其中有几个点可以由任意点所到达
求强连通分量然后缩点,找到出度为零的强连通分量,如果出度为零的强连通分量大于一个,则答案不存在,否则答案为该强连通分量中点的个数。
先用Korasaju算法做了一遍,这个比较好理解,正着dfs一遍标记结束时间,然后根据结束时间从后到前对反图做一遍dfs求连通块,求得的连通块即为一个强连通分量。
#include <stdio.h>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
const int Max=10050;
struct edge{
int to,nxt;
}e1[Max*5],e2[Max*5];
int h1[Max],h2[Max];
int siz1,siz2;
int vis1[Max],vis2[Max];
int be[Max],cnt[Max],out[Max];
int st[Max],stz;
int tot;
struct node{
int u,v;
}e[Max*5];
void init(){
memset(e1,-1,sizeof(e1));
memset(e2,-1,sizeof(e2));
memset(h1,-1,sizeof(h1));
memset(h2,-1,sizeof(h2));
siz1=siz2=stz=tot=0;
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
memset(be,0,sizeof(be));
memset(cnt,0,sizeof(cnt));
memset(out,0,sizeof(out));
}
void add(int u,int v){
e1[++siz1].nxt=h1[u];e1[siz1].to=v;h1[u]=siz1;
e2[++siz2].nxt=h2[v];e2[siz2].to=u;h2[v]=siz2;
}
void dfs1(int rt){
vis1[rt]=1;
for(int i=h1[rt];~i;i=e1[i].nxt){
int to=e1[i].to;
if(!vis1[to])dfs1(to);
}
st[++stz]=rt;
}
void dfs2(int rt){
vis2[rt]=1;
cnt[tot]++;
for(int i=h2[rt];~i;i=e2[i].nxt){
int to=e2[i].to;
if(!vis2[to])dfs2(to);
}
be[rt]=tot;
}
int main(void)
{
int n,m;
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&e[i].u,&e[i].v);
add(e[i].u,e[i].v);
}
for(int i=1;i<=n;i++){
if(!vis1[i])dfs1(i);
}
for(int i=stz;i>=1;i--){
if(!vis2[st[i]]){
++tot;
dfs2(st[i]);
}
}
for(int i=1;i<=m;i++){
if(be[e[i].u]!=be[e[i].v])out[be[e[i].u]]++;
}
int ans=0;
int flag=0;
for(int i=1;i<=tot;i++){
if(out[i]==0){
if(ans){flag=-1;break;}
else {
ans++;
flag=i;
}
}
}
if(flag==-1)puts("0");
else printf("%d\n",cnt[flag]);
return 0;
}
接下来用tarjan做一遍,tarjan的优势在于无需建立反图,只需一遍dfs,比较快,根据dfn和low的值就可以求出强连通分量了。
学习资料[转]:请参考https://www.byvoid.com/blog/scc-tarjan/
下面贴代码:
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
using namespace std;
struct node{
int to,nxt;
}e[50050];
struct edge{
int u,v;
}ei[50050];
int h[10010];
int myst[10010];
int vis[10010];
int belong[10010];
int cnt[10010];
int out[10010];
int dfn[10010],low[10010];
int st,siz,cn,idx;
void init(){
memset(h,-1,sizeof h);
memset(e,-1,sizeof e);
memset(vis,0,sizeof vis);
memset(belong,0,sizeof belong);
memset(cnt,0,sizeof cnt);
memset(out,0,sizeof out);
st=siz=cn=idx=0;
}
void add(int u,int v){
e[++siz].to=v;
e[siz].nxt=h[u];
h[u]=siz;
}
void tarjan(int u){
dfn[u]=low[u]=++idx;
vis[u]++;
myst[++st]=u;
for(int i=h[u];~i;i=e[i].nxt){
int v=e[i].to;
if(!vis[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]==1){
low[u]=min(low[u],dfn[v]);
}
}
int v;
if(dfn[u]==low[u]){
++cn;
do{
v=myst[st--];
belong[v]=cn;
vis[v]++;
cnt[cn]++;
}while(u!=v);
}
}
int main(){
int n,m;
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&ei[i].u,&ei[i].v);
add(ei[i].u,ei[i].v);
}
for(int i=1;i<=n;i++)if(!vis[i])tarjan(i);
for(int i=1;i<=m;i++){
if(belong[ei[i].u]!=belong[ei[i].v]){
out[belong[ei[i].u]]++;
}
}
int flag=0;
int ans=0;
for(int i=1;i<=cn;i++){
if(out[i]==0){
if(flag){ans=0;break;}
else {flag++;ans=cnt[i];}
}
}
printf("%d\n",ans);
}