图论 -Tarjan算法
来源:互联网 发布:2017年网络热点话题 编辑:程序博客网 时间:2024/06/06 06:57
- Tarjan算法的引入
- 算法流程
- 应用和模板题
- 洛谷P3387
- 洛谷P3388
Tarjan算法的引入
“tarjan陪伴强联通分量
生成树完成后思路才闪光
欧拉跑过的七桥古塘
让你 心驰神往”—《膜你抄》
tarjan算法是基于对有向图的深度优先搜索的算法,主要用于求解强连通分量,时间复杂度是线性的 O(n+m)其中n为点数,m为边数。tarjan的算法关键在搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量,具体实现这一算法,我们需要使用一些辅助数组,其意义如下所述:
dfn[ ]:时间戳数组,表示这个点在dfs时被搜索到的顺序;
low[ ]:时间戳数组,表示回溯时点被搜索到的顺序;
flag[ ]:布尔型数组,标记某个点是否被访问;
stack[ ]:模拟栈的功能的数组,某些情况可能不需要这一数组;
算法流程
下面用文字来描述一下算法的具体流程:
1.首先从节点1开始dfs,将遍历到的节点加入栈中,如果发现dfn[u]=low[u],则找到了强连通分量,退栈直到u=v;
2.回溯,发现dfn[v]=low[v],{v}为强连通分量;
3.继续返回节点1搜索,至所有节点都被访问,算法结束
应用和模板题
洛谷P3387
缩点模板
用tarjan求解强连通分量,将强连通分量缩点后重新建图,最后跑一遍spfa求最大值。
#include<bits/stdc++.h>using namespace std;const int MAXM=100010;const int MAXN=10010;int head[MAXM],val[MAXM],x[MAXM],y[MAXM],dis[MAXM],f[MAXM];int dfn[MAXM],low[MAXM],color[MAXM],s[MAXM];int n,m,tmp,t,ct,top,ans;bool flag[MAXN];struct Edge { int to; int from; int next;} edge[MAXM];void init() { memset(head,0,sizeof(head)); memset(flag,false,sizeof(flag)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); tmp=t=top=ans=0;}void add(int from,int to) { tmp++; edge[tmp].to=to; edge[tmp].from=from; edge[tmp].next=head[from]; head[from]=tmp;}void tarjan(int now) { dfn[now]=low[now]=++t; flag[now]=true; s[++top]=now; for(int i=head[now],v=edge[i].to; i>0; i=edge[i].next,v=edge[i].to) { if(dfn[v]==0) { tarjan(v); low[now]=min(low[now],low[v]); } else if(flag[v]) { low[now]=min(low[now],dfn[v]); } } if(dfn[now]==low[now]) { ct++; flag[now]=false; while(s[top+1]!=now){ color[s[top]]=ct; f[ct]+=val[s[top]]; ans=max(ans,f[ct]); flag[s[top]]=false; top--; } }}void spfa(int x) { memset(dis,0,sizeof(dis)); memset(flag,0,sizeof(flag)); dis[x]=f[x]; queue <int> q; flag[x]=true; q.push(x); while(!q.empty()) { int u=q.front(); q.pop(); flag[u]=false; for(int i=head[u],v=edge[i].to; i>0; i=edge[i].next,v=edge[i].to) { if(dis[v]<dis[u]+f[v]) { dis[v]=dis[u]+f[v]; if(!flag[v]) { flag[v]=true; q.push(v); } } } } for(int i=1; i<=ct; i++) { ans=max(dis[i],ans); }}int main() { init(); scanf("%d %d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&val[i]); } for(int i=1; i<=m; i++) { int from,to; scanf("%d %d",&from,&to); x[i]=from; y[i]=to; add(from,to); } for(int i=1; i<=n; i++) { if(dfn[i]==0) tarjan(i); } tmp=0; memset(head,0,sizeof(head)); memset(edge,0,sizeof(edge)); for(int i=1;i<=m;i++){ if(color[x[i]]!=color[y[i]]) add(color[x[i]],color[y[i]]); } for(int i=1;i<=ct;i++){ spfa(i); } printf("%d\n",ans); return 0;}
洛谷P3388
求割点的模板
割点就是删去了这个点后图变为不再连通的点
判根节点是否为割点非常简单,对于不是根的节点,如果有
cnt不要对重复的点多次计数。
#pragma GCC optimize(3)#include<bits/stdc++.h>using namespace std;const int MAXN=200010;int ans[MAXN],p[MAXN],dfn[MAXN],low[MAXN],head[MAXN];bool res[MAXN],flag[MAXN];int tmp=0,t=0,cnt=0;int n,m;struct Edge { int to; int next;} edge[MAXN];void init() { for(int i=1;i<=n;i++){ head[i]=0;dfn[i]=0;low[i]=0;p[i]=i; }}void add(int from,int to) { tmp++; edge[tmp].next=head[from]; edge[tmp].to=to; head[from]=tmp;}void tarjan(int now) { int child=0; dfn[now]=low[now]=++t; for(int i=head[now]; i>0; i=edge[i].next) { int v=edge[i].to; if(!dfn[v]) { p[v]=p[now]; tarjan(v); low[now]=min(low[now],low[v]); if(now!=p[now]&&low[v]>=dfn[now]){ if(res[now]==false) cnt++; res[now]=true; } if(now==p[now]) child++; } low[now]=min(low[now],dfn[v]); } if(now==p[now]&&child>=2) { if(res[now]==false) cnt++; res[now]=true; }}int main() { scanf("%d %d",&n,&m); init(); for(int i=1;i<=m;i++){ int x,y; scanf("%d %d",&x,&y); add(x,y); add(y,x); } for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } printf("%d\n",cnt); for(int i=1;i<=n;i++){ if(res[i]==true) printf("%d ",i); }}
阅读全文
1 0
- 图论Tarjan算法笔记
- 图论1 Tarjan算法
- 图论 -Tarjan算法
- 图论 LCA离线算法 Tarjan
- tarjan算法
- Tarjan算法
- tarjan算法
- Tarjan算法
- Tarjan算法
- Tarjan算法
- Tarjan 算法
- Tarjan算法
- Tarjan算法
- tarjan算法
- Tarjan算法
- tarjan算法
- tarjan算法
- Tarjan算法
- 11月9日
- hdu 1505City Game
- 实验一:写一个hello world小程序
- Ten Years of Pedestrian Detection,What Have We Learned? 知识笔记
- 新博客https://home.cnblogs.com/u/hua-dong/
- 图论 -Tarjan算法
- java项目乱码处理
- Monkey的APK集合测试的设置方法
- bzoj1493
- 一个简单的压缩成tar.gz文件的shell脚本
- [编程题] 藏宝图
- 6.4
- 指针问题梳理
- git问题:You have not concluded your merge (MERGE_HEAD exists)