关于对Tarjan算法的思考与尝试
来源:互联网 发布:幻想神域攻略软件 编辑:程序博客网 时间:2024/06/04 19:19
Tarjan
–关于对Tarjan算法的思考与尝试
接下来(超级)详细的解释一下代码吧!
全局变量部分的解释
int i,j,n,m;bool b[1001];int color[1001],colorn;int stack[1001],top;//数组模拟栈 int s,e,temp,index;int dfn[1001],low[1001];int head[1001];struct data{ int v; data *nxt;}a[100001];
i,j:变量。
n:点数。
m:边数。
b[]:在有向图中某个点是否经历过(布尔)。
stack[]:数组模拟栈的操作(其实就是一个数组啦~)
top:模拟栈顶,通过top–来模拟pop操作。
color[]:表示这是第几个已确定的强连通分量。
colorn:是一个累加器,记录已经确定的强连通分量个数,便于为强连通分量编号。
s,e,temp:变量。
index:累加器,是一个时间戳,来记录遍历过的节点数。
DFN[ i ] : 在DFS中该节点被搜索的次序(时间戳)
LOW[ i ] : 为i或i的子树能够追溯到的最早的栈中节点的次序号
当DFN[ i ]==LOW[ i ]时,为i或i的子树可以构成一个强连通分量。
struct内部的东西就是图论的基本功啦,如果不会请移步至链表入门。
读入优化
int r(){ char ch=getchar(); int ans=0; while(ch<'0'||ch>'9') { ch=getchar(); } while(ch>='0'&&ch<='9') { ans*=10; ans+=ch-'0'; ch=getchar(); } return ans;}
插入节点
这也是基本功。如果不会可以借鉴解释 in SPFA入门。在这里不再赘述。
int ins(int ss,int ee){ temp++; a[temp].nxt=&a[head[ss]]; head[ss]=temp; a[temp].v=ee;}
Tarjan算法
核心在这里↓↓↓
void tarjan(int x){ dfn[x]=++index; low[x]=index; b[x]=1; stack[++top]=x; data *p=&a[head[x]]; while(p->v!=0) { int vv=p->v; if(!dfn[vv]) { tarjan(vv); low[x]=min(low[x],low[vv]); } else if(b[vv]) { low[x]=min(low[x],dfn[vv]); } p=p->nxt; } if(dfn[x]==low[x]) { b[x]=0; color[x]=++colorn; while(stack[top]!=x) { color[stack[top]]=colorn; b[stack[top--]]=0; } top--; }}
下面详细解释:
tarjan算法首先是有一个类似于DFS的过程,如果不会DFS,那就……呃~~(╯﹏╰)……就请关闭此页。
首先从1号点开始深度优先搜索,每搜一个他的DFN[]=经历过的点数,即++index,LOW[]为栈中最早的与其相连的点的次序号。
当搜到某个点恰好没有出度了,就停止搜索,开始判断,如果DFN==LOW那么他自己就是一个强联通分量。
以此类推往前回退,如果对应点的下一条边不是NULL,就往下一条路走,而且不能走已经被访问过的节点。
然后如果在队列里再一次搜到栈中已有的元素,就使LOW=MIN(LOW[],DFN[])。
如果对于一个出发点x,他的终点之一vv没有被访问过,就继续深搜,这个递推过程完成后,LOW[x]=min(LOW[x],LOW[vv]),来让他们的根节点尽量小,这是我们人为设定的标准。当然了根节点向数字大的方向规定也行。
主函数
包括输入输出过程等。
int main(){ n=r(),m=r(); for(i=1;i<=m;i++) { s=r(),e=r(); ins(s,e); } for(i=1;i<=n;i++) if(!col[i]) tarjan(i); for(i=1;i<=colorn;i++) { for(j=1;j<=n;j++) if(color[j]==i) cout<<j<<" "; cout<<endl; }}
Tarjan的简要步骤(蒟蒻的总结)
1. 建立一个有向图,用链表存
2. 以1为起始点往后深搜至第一次搜
到头为止,每搜一次DFN时间戳与LOW
+1。
3. 如果DFN[]=LOW[],就是一个根节
点,那么他就是一个强连通分量。
4. 以此类推往前回退,如果对应点
的下一个点不是NULL,就往下一条路
走,而且不能走已经被访问过的节点
。然后如果在队列里再一次搜到下一
元素就使MIN(LOW[],DFN[])。 、
最后给大家推荐一个网页,大家可以通过例子更好的理解:
http://www.cnblogs.com/uncle-lu/p/5876729.html
- 关于对Tarjan算法的思考与尝试
- 对无效尝试的思考
- 关于tarjan算法的应用
- 使用多窗体时, 关于节约内存和加快启动速度的思考与尝试
- 关于算法的思考
- Mzc和体委的争夺战(Dijkstra算法的思考与尝试以及与SPFA算法的对比)
- bzoj2140对tarjan算法的一些理解
- 对连连看一种算法的分析与思考
- 关于对记录的思考
- 对算法问题的思考
- 关于网站抽奖活动算法的尝试
- 关于遮挡剔除的几个算法尝试
- 关于Rocchio分类算法的总结与思考
- 【数据结构与算法】关于二叉查找树的思考
- [科研笔记] 关于人工智能与算法项目的思考
- 从 VCL 中吸取营养--使用多窗体时, 关于节约内存和加快启动速度的思考与尝试
- 关于项目算法的思考
- 关于分类算法的思考
- DNS域名解析过程
- Driver中使用的内核机制
- Unity3D 编写游戏运行时间 格式为00:00:00
- [bzoj3653]谈笑风生 主席树
- Java 类加载机制
- 关于对Tarjan算法的思考与尝试
- Java集合-常用集合类
- 基于binder机制编写aidl接口文件
- MySQL中触发器
- spring框架学习(三)junit单元测试
- LoadRunner实战小例子(在线预订机票)
- PL/SQL
- An in-depth look into the ARM virtualization extensions
- 知识记录