算法导论-第22章-基本的图算法-22.5 强连通分量
来源:互联网 发布:php的转义字符有哪些 编辑:程序博客网 时间:2024/05/22 23:22
转自
#include <iostream>using namespace std;//8个点#define N 8 #define WHITE 0#define GRAY 1#define BLACK 2//边结点结构struct Edge{ int start;//有向图的起点 int end;//有向图的终点 Edge *next;//指向同一个起点的下一条边 int type;//边的类型 Edge(int s, int e):start(s),end(e),next(NULL){}};//顶点结点结构struct Vertex{ int id; Edge *head;//指向以该顶点为起点的下一条边 int color;//顶点的颜色 Vertex *p;//指向遍历结果的父结点 int d, f;//第一次被发现的时间和结束检查的时间 Vertex( ):head(NULL),color(WHITE),p(NULL),d(0x7fffffff),id(0){}};//图结构struct Graph{ Vertex V[N+1];//N个顶点 Graph() { int i; for(i = 1; i <= N; i++) V[i].id=i; }};int time = 0;bool flag = 0;//flag为0表示第一次调用DFS,为1表示第二次调用DFSint Sort[N+1] = {N};//存储按u.f从大到小排序时的点,即sort[1]存储的点的f值最大,sort[N]存储的点的f值最小,按这个点的顺序调用DFS_Visit函数//插入边,按边的end由小到大排列void InsertEdge(Graph *G, int start , int end){ Edge *E = new Edge(start,end); //如果当前点E->start的链表为空,则把E边作为head if(G->V[E->start].head == NULL) G->V[E->start].head =E; //如果有,加入到链表中,递增顺序排列,便于查重 else { //链表的插入 Edge *e1 = G->V[E->start].head, *e2 = e1; while(e1 && e1->end < E->end) { e2 = e1; e1 = e1->next; } //插入了重复的边,直接返回 if(e1 && e1->end == E->end) return; //第一条边的end都比E边的end大, 此时e1 == e2,则把E作为head if(e1 == e2) { E->next = e1; G->V[E->start].head =E; } //找到E的正确位置 else { e2->next = E; E->next = e1; } }}//转置,重新构造一个图Graph* Reverse(Graph *G) { Graph *ret = new Graph; int i; //遍历图G中的每一条边,以终点为起点,以起点为终点,加入到新图RET中 for(i = 1; i <= N; i++) { Edge *E = G->V[i].head; while(E) { InsertEdge(ret, E->end, E->start); E = E->next; } } return ret; }//访问某顶点void DFS_Visit(Graph *G, Vertex *u){ //在第二次DFS调用时输出 if(flag) cout<<u->id<<' '; //将u置为黑色 u->color = GRAY; //使全局变量time增值 time++; //将time的新值记录为发现时间 u->d = time; //检查和u相邻的每个顶点v Vertex *v; Edge *e = u->head; while(e) { v = &G->V[e->end]; //如果顶点为白色 if(v->color == WHITE) { //递归访问顶点 v->p = u; DFS_Visit(G, v); //树边 e->type = 1; } else if(v->color == GRAY) { //反向边 e->type = 2; } else if(v->color == BLACK) { //正向边 if(u->d < v->d) e->type = 3; //交叉边 else e->type = 4; } e = e->next; } //以u为起点的所有边都被探寻后,置u为黑色 u->color = BLACK; //并将完成时间记录在f[u]中 time++; u->f = time; //把结果按照f从大到小的顺序保存于Sort数组中 if(flag == 0) { Sort[Sort[0]] = u->id; Sort[0]--; }}//深度优先搜索void DFS(Graph *G){ int i; //对每个顶点初始化 for(i = 1; i <= N; i++) { G->V[i].id = i; G->V[i].color = WHITE; G->V[i].p = NULL; } //时间戳初始化 time = 0; //依次检索V中的顶点,发现白色顶点时,调用DFS_Visit访问该顶点 for(i = 1; i <= N; i++) { int j; //第一次是以正常顺序按点1->2->3->.....->8的顺序调用DFS_Visit函数 if(flag == 0) j = i; //第二次是以f从大到小的顺序,这个顺序在第一次dfs次保存于Sort数组中 else j = Sort[i]; //发现白色顶点时,调用DFS_Visit访问该顶点 if(G->V[j].color == WHITE) { if(flag) cout<<"强连通分量为:"; DFS_Visit(G, &G->V[j]); //flag == 1时,第二次调用DFS,此时每次调用DFS_Visit 就会输出一个强连通分量,换行后,再调用,又输出一个强连通分量 if(flag) cout<<endl; } }}void Strongly_Connected_Component(Graph *G){ //第一次DFS,计算每个顶点的f DFS(G); //转置,计算GT Graph *G2 = Reverse(G); //第一次的DFS和第二次的DFS不同,用flag区分 flag = 1; //第二次的DFS,按照f从大到小的顺序调用 DFS(G2);}/* 1 →2→ 3 ↔ 4↓↑ ↙↓ ↓ ↓ 5 → 6 ↔ 7 →8 上面8还要指向自己,共15条边*/int main() { //构造一个空的图 Graph *G = new Graph; //15条边 int edge[16][2] = {{0,0},{1,2},{1,5},{2,3},{2,5},{2,6},{3,4},{3,7},{4,3},{4,8},{5,1},{5,6},{6,7},{7,6},{7,8},{8,8}}; for(int i = 1; i <= 15; i++) { int start = edge[i][0]; int end = edge[i][1]; InsertEdge(G, start , end); } //计算强联通分量 Strongly_Connected_Component(G); return 0; }
阅读全文
0 0
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- 算法导论-第22章-基本的图算法:强连通分量(深度优先遍历基础上)C++实现
- 算法导论 第22章 图的基本算法(四) 强连通分支
- 算法导论 强连通分量
- 第22章:基本的图算法—拓扑排序和有向图强连通分量
- 《算法导论》笔记 第22章 22.5 强连通分支
- 算法导论-证明强连通分量算法
- 算法导论 第22章 图的基本算法 22.5 强联通分支
- 算法导论22.5强连通分量 练习总结
- 算法导论 ch22 注记 有向图强连通分量的Tarjan算法
- 图算法:强连通分量
- 强连通分量算法
- 算法导论 第23章 广度优先搜索 深度优先搜索 拓扑排序 强连通分量 C++实现
- 强连通分量算法; 重在理解原理分析 ; 算法导论讲的很明白;
- 强连通分量的三种算法
- 强连通分量的三种算法
- 求强连通分量的Tarjan算法
- Linux shell脚本功略第2版笔记--第二章
- 数据结构实验之栈七:出栈序列判定
- WEB环境搭建 各服务软件版本汇聚
- JavaPoi技术二-------导出数据到Excel以及从excel中读取数据
- (转)Android一款界面良好使用简单的弹出框
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- 卸载 oracle
- CSS学习笔记
- 提高办事效率的工具
- 安卓控件
- 左偏树总结
- java 去按钮边框及焦点
- 进制转换-zxc
- 使用OpenMP实现并行归并排序(Report)