强连通分量
2017-07-28 15:30
204 查看
讲解
一道模板题
牛的舞会The Cow Prom#include<iostream> #include<cstdio> using namespace std; int n,m,to[1000001],nxt[100001],head[1000001]; int edge,dfn[100001],low[100001],xx,yy,ans,top,time; bool in[1000001]; int duilie[100001],mmp,pc; void tarjan(int pccc) { dfn[pccc]=low[pccc]=++time; duilie[++top]=pccc; in[pccc]=1; for(int i=head[pccc];i;i=nxt[i]) { int t=to[i]; if(!dfn[t])//没有走到过 { tarjan(t); if(low[t]<low[pccc]) low[pccc]=low[t]; } else//这个点之前已经走过了,并且是当前节点的祖先 { if(low[pccc]>dfn[t]&&in[t]==1) low[pccc]=dfn[t];//用t的dfn值更新,low值好像也行。。 } } if(dfn[pccc]==low[pccc])//出栈 { pc=0; while(duilie[top]!=pccc) { in[duilie[top]]=0; top--; pc++; } top--; in[duilie[top]]=0; if(pc>=1) ans++; } } int main() { // freopen("1.txt","r",stdin); cin>>n>>m; for(int i=1;i<=m;i++)//建图 { scanf("%d%d",&xx,&yy); edge++; to[edge]=yy; nxt[edge]=head[xx]; head[xx]=edge; } for(int i=1;i<=n;i++)//有些点是不连通的 { if(!dfn[i]) tarjan(i); } printf("%d",ans); }
洛谷上一个大神写的,我和他的思路很像qwq
感觉他写的更好。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100001 using namespace std; bool vis ; int n,m,x,y,tim,tot,top,sum; int head ,dfn ,low ,stack ,belong ; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } struct Edge { int from,next,to; }edge ; int add(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot; } int tarjan(int now) { dfn[now]=low[now]=++tim; stack[++top]=now;vis[now]=true; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(vis[t]) low[now]=min(low[now],dfn[t]); else if(!dfn[t]) tarjan(t),low[now]=min(low[now],low[t]); } if(low[now]==dfn[now]) { sum++;belong[now]=sum; int ans=1; for(;stack[top]!=now;top--) { vis[stack[top]]=false; belong[stack[top]]=sum; ans++; } vis[now]=false;top--; if(ans==1) sum--; } } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) x=read(),y=read(),add(x,y); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); printf("%d",sum); return 0; }
缩点
刻录光盘
应该是个假缩点。。tarjan一遍后遍历每个点和这个点连的所有边,记录好每一个点的belong,统计每一个强连通分量的入度,入度为0,ans++。qwq
我觉得我这个代码比上边的好。。
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int n,nxt[1000001],head[1000001],to[1000001],x,y,edge,time,belong[1000001],cnt,top; int stack[100001],ru[1000001],ans,dfn[1000001],low[1000001],pc; bool in[100001]; void add(int x,int y) { edge++; to[edge]=y; nxt[edge]=head[x]; head[x]=edge; } void tarjan(int x) { dfn[x]=low[x]=++time; in[x]=1;stack[++top]=x; for(int i=head[x];i;i=nxt[i]) { int t=to[i]; if(!dfn[t]) { tarjan(t); low[x]=min(low[x],low[t]); } else { if(in[t]) low[x]=min(low[x],dfn[t]); } } if(dfn[x]==low[x]) { cnt++; do { pc=stack[top]; belong[pc]=cnt; in[pc]=0; top--; } while(pc!=x);//非常容易出错的细节,这里的pc是上一个stack[top],而之后的一步top--,可以拿只有一个点的强连通分量模拟 } } int main() { cin>>n; for(int i=1;i<=n;i++) { while(scanf("%d",&x)&&x) { add(i,x); } } for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } for(int i=1;i<=n;i++) { for(int j=head[i];j;j=nxt[j]) { int t=to[j]; if(belong[t]!=belong[i]) ru[belong[t]]++; } } for(int i=1;i<=cnt;i++) { if(ru[i]==0) ans++; } printf("%d",ans); }
消息扩散
和上题一样,一模一样。#include<iostream> #include<cstdio> #define maxn 1500001 using namespace std; int n,m,to[600001],nxt[600001],head[600001],dfn[maxn],low[maxn],belong[maxn],ru[maxn]; bool in[maxn]; int e,xx,yy,stack[600001],top,time,pc,cnt,ans; void tarjan(int x) { stack[++top]=x; dfn[x]=low[x]=++time; in[x]=1; for(int i=head[x];i;i=nxt[i]) { int t=to[i]; if(!dfn[t]) { tarjan(t); low[x]=min(low[t],low[x]); } else { if(in[t]) { low[x]=min(low[x],dfn[t]); } } } if(dfn[x]==low[x]) { cnt++; do { pc=stack[top]; belong[pc]=cnt; top--; in[pc]=0; } while(pc!=x); } } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { scanf("%d%d",&xx,&yy); e++; to[e]=yy; nxt[e]=head[xx]; head[xx]=e; } for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } for(int i=1;i<=n;i++) { for(int j=head[i];j;j=nxt[j]) { int t=to[j]; if(belong[t]!=belong[i]) ru[belong[t]]++; } } for(int i=1;i<=cnt;i++) { if(ru[i]==0) ans++; } printf("%d",ans); }
相关文章推荐
- 有向图连通分量SCC
- 点连通分量
- hdu 4587 2013南京邀请赛B题/ / 求割点后连通分量数变形。
- C 语言实现二次遍历法提取图像连通分量最大值
- poj1523--C - SPF(连通分量,求割点)
- 强连通分量(桥)
- Critical Set(删除无向图的一个节点或者两个节点或者三个节点之后有几个连通分量?)
- 数据结构之无向图的连通分量和生成树
- 强连通分量
- 有向图强连通分量的Tarjan算法
- Codeforces Round #286 div.2 D 505D. Mr. Kitayuta's Technology【强连通分量,弱联通分量】
- poj 2186 有向图强连通分量
- 重连通分量模版
- 强连通分量
- 数据结构实验:连通分量个数(并查集)
- tarjan算法之 强连通分量
- 强连通分量-kosaraju算法
- Tarjan 求强连通分量
- tarjan算法-解决有向图中求强连通分量的利器
- 强连通分量的tarjan算法应用(一)