强连通分量
来源:互联网 发布:淘宝赚钱方法 编辑:程序博客网 时间:2024/06/05 09:37
讲解
一道模板题
牛的舞会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 100001using namespace std;bool vis[N];int n,m,x,y,tim,tot,top,sum;int head[N],dfn[N],low[N],stack[N],belong[N];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[N];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 1500001using 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);}
阅读全文
0 0
- 收缩强连通分量
- 强连通分量
- POJ2181强连通分量
- 强连通分量模板
- POJ_2762_强连通分量
- 强连通分量
- 强连通分量
- 强连通分量
- 强连通分量
- 【强连通分量】传话
- 强连通分量 关节点
- poj2186强连通分量
- 强连通分量
- 强连通分量
- 强连通分量模板
- 强连通分量
- 强连通分量tarjan
- 强连通分量scc
- 为控件设置某几个边的边框
- 服务机器人的普及与这三方面因素紧紧相关
- vulkan安装流程
- DOM对象,控制HTML元素
- Python3《机器学习实战》学习笔记(三):决策树实战篇之为自己配个隐形眼镜
- 强连通分量
- Ubuntu创建新用户并增加管理员权限
- 关于java中关闭数据库链接的正确写法
- 钓鱼Wi-Fi搭建实践
- 芝麻信用分800+的技巧,get!
- 图像配准之《常用图像变换模型》简述
- OSI七层框架与TCP/IP四层框架
- java abstract修饰符
- java-面试题3