使用广度优先搜索生成关键路径
2017-06-07 10:06
330 查看
/* Name: 拓扑排序之关键路径 Copyright: Author: 巧若拙 Date: 17-11-14 21:02 Description: 拓扑排序之关键路径 若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续时间), 则此带权的有向图称为边表示活动的网 (Activity on Edge Network) ,简称 AOE 网。 (1)AOV 网具有的性质 ⒈ 只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始。 ⒉ 只有在进入某一顶点的各有向边所代表的活动都已经结束,该顶点所代表的事件才能发生。 ⒊ 表示实际工程计划的 AOE 网应该是无环的,并且存在唯一的入度过为 0 的开始顶点和唯一的出度为 0 的完成顶点。 (2)由事件 v j 的最早发生时间和最晚发生时间的定义 , 可以采取如下步骤求得关键活动 : 1. 从开始顶点 v 1 出发 , 令 ve(1)=0, 按拓朴有序序列求其余各顶点的可能最早发生时间。 Ve(k)=max{ve(j)+dut(<j,k>)} ( 7.1 ) j ∈ T 其中 T 是以顶点 v k 为尾的所有弧的头顶点的集合 (2 ≤ k ≤ n) 。 如果得到的拓朴有序序列中顶点的个数小于网中顶点个数 n ,则说明网中有环,不能求出关键路径,算法结束。 2. 从完成顶点 v n 出发,令 vl(n)=ve(n) ,按逆拓朴序列求其余各顶点的允许的最晚发生时间 : vl(j)=min{vl(k)-dut(<j,k>)} k ∈ S 其中 S 是以顶点 v j 是头的所有弧的尾顶点集合 (1 ≤ j ≤ n-1) 。 3. 求每一项活动 a i (1 ≤ i ≤ m) 的最早开始时间 e(i)=ve(j) ;最晚开始时间 l(i)=vl(k)-dut(<j,k>) 。若某条弧满足 e(i)=l(i) ,则它是关键活动。 输入: 第一行两个整数n,m分别表示顶点个数和边的条数,其中顶点的编号为0~n-1。 接下来的m行,每行有三个数u,v,w,表示从弧尾u到弧头v的边的权值w。 8 9 0 1 5 0 2 4 1 4 3 2 3 2 3 4 2 4 5 6 4 6 6 5 7 2 6 7 2 输出: 输出所有关键路径,每行输出一个关键路径。格式如下: 0->2->3->4->5->7 0->2->3->4->6->7 0->1->4->5->7 0->1->4->6->7 算法分析: 采用广度优先搜索进行拓扑排序,获取拓扑序列的同时计算各顶点事件的最早发生时间,然后逆序计算各顶点事件的最晚发生时间。 本文是《大话数据结构》的读书笔记,但算法实现与《大话数据结构》完全不同,自我感觉比书上的算法要简洁,哈哈! */ #include<stdio.h> #include<stdlib.h> #define MAXN 26 //最大顶点数量 #define MAXM 100000 //最大边数量 typedef char VertexType; //顶点类型由用户自定义 typedef int EdgeType; //边上的权值类型由用户自定义 typedef struct EdgeNode{ //边表结点 int adjvex; //邻接点域,存储该顶点对应的下标 EdgeType weight; //权值,对于非网图可以不需要 struct EdgeNode *next; //链域,指向下一个邻接点 } EdgeNode; typedef struct VertexNode{ //顶点表结点 VertexType data; //顶点域,存储顶点信息 int in; //存储顶点入度的数量 EdgeNode *firstEdge; //边表头指针 } VertexNode; void PrintGraph(VertexNode GL[], int n);//输出图 int TopoLogicalSort(int topo[], int Etv[], VertexNode GL[], int n); void CriticalPath(VertexNode GL[], int n);//求关键路径 void PrintPath(VertexNode GL[], int Etv[], int Ltv[], int path[], int top, int end);//深度优先搜索输出关键路径 int main() { int i, m, n; int u, v; EdgeType w; VertexNode GL[MAXN]; //存储顶点表结点信息 EdgeNode *e; for (i=0; i<MAXN; i++)//初始化图 { GL[i].data = i; GL[i].in = 0; GL[i].firstEdge = NULL; } printf("请输入顶点数量和边数量:"); scanf("%d%d", &n, &m); for (i=0; i<m; i++) { scanf("%d%d%d", &u, &v, &w); e =(EdgeNode*)malloc(sizeof(EdgeNode)); //采用头插法插入边表结点 if (!e) { puts("Error"); exit(1); } e->adjvex = v; e->weight = w; e->next = GL[u].firstEdge; GL[u].firstEdge = e; GL[v].in++; } PrintGraph(GL, n); CriticalPath(GL, n);//求关键路径 system("pause"); return 0; } void PrintGraph(VertexNode GL[], int n)//输出图 { int i, j; EdgeNode *e; for (i=0; i<n; i++) { printf("G[%d] = %c: ", i, i+'a'); for(e=GL[i].firstEdge; e!=NULL; e=e->next) { printf("->%d,%d", e->adjvex, e->weight); } printf("\n"); } printf("\n"); } int TopoLogicalSort(int topo[], int Etv[], VertexNode GL[], int n) { int i, k, front, rear; EdgeNode *e; front = rear = 0; for (i=0; i<n; i++)//将入度为0的顶点入队列 { Etv[i] = 0; //初始化各事件最早发生事件为0 if (GL[i].in == 0) { topo[rear++] = i; } } while (front < rear)//采用广度优先搜索获取拓扑序列 { k = topo[front++]; for(e=GL[k].firstEdge; e!=NULL; e=e->next)//将u的邻接点入度减1,并将入度为0的顶点入栈 { if (--GL[e->adjvex].in == 0) { topo[rear++] = e->adjvex; } if (Etv[e->adjvex] < Etv[k] + e->weight)//更新各顶点事件的最早发生时间 { Etv[e->adjvex] = Etv[k] + e->weight; } } } return (rear == n);//如果count小于顶点数,说明存在环 } void CriticalPath(VertexNode GL[], int n)//求关键路径 { int i, j; int topo[MAXN], path[MAXN]; int Etv[MAXN] = {0}, Ltv[MAXN];//存储事件的最早和最晚发生时间 EdgeNode *e; if (!TopoLogicalSort(topo, Etv, GL, n)) { puts("不存在关键路径"); return; } for (i=0; i<n; i++) { Ltv[i] = Etv[topo[n-1]]; //初始化各事件最晚发生事件为最后一个事件发生的时间 } for (j=n-2; j>=0; j--) { for(e=GL[topo[j]].firstEdge; e!=NULL; e=e->next)//将u的邻接点入度减1,并将入度为0的顶点入栈 { if (Ltv[topo[j]] > Ltv[e->adjvex] - e->weight)//更新各顶点事件的最晚发生时间 { Ltv[topo[j]] = Ltv[e->adjvex] - e->weight; } } } path[0] = topo[0]; PrintPath(GL, Etv, Ltv, path, 1, topo[n-1]); } void PrintPath(VertexNode GL[], int Etv[], int Ltv[], int path[], int top, int end)//深度优先搜索输出关键路径 { int i, u = path[top-1]; EdgeNode *e; if (u == end) { printf("%d", path[0]); //输出关键路径 for (i=1; i<top; i++) { printf("->%d", path[i]); } printf("\n"); } else { for(e=GL[path[top-1]].firstEdge; e!=NULL; e=e->next) { if (Etv[e->adjvex] == Ltv[e->adjvex] && Ltv[e->adjvex] - e->weight == Ltv[u])//关键事件和关键路径 { path[top++] = e->adjvex; //入栈 PrintPath(GL, Etv, Ltv, path, top, end); top--; //退栈 } } } }
相关文章推荐
- 数据结构学习_图(1)深度优先搜索、广度优先搜索和最小生成树
- 图与路径(深度优先,广度优先,最小生成树)
- 哈理工OJ 1316 移动 II (广度优先搜索+路径打印)
- Beam Search 简介 原创 2016年06月01日 11:41:18 标签:搜索 /beam-searc 5087 概要 传统的广度优先策略能够找到最优的路径,但是在搜索空间非常大的情况下,内
- 图论(三)------广度优先搜索与单源无权最短路径
- hdu 1026 Ignatius and the Princess (广度优先搜索+路径打印)
- BFS-迷宫问题-用宽度(广度)优先搜索解决最优路径问题
- c++ 使用广度优先算法走迷宫并标记路径
- 广度优先搜索迷宫的最短路径走法!
- (原创)广度优先搜索解决最短路径问题
- 图的分支生成:对稀疏的无向图,在度数不等于2的节点处,将图“拆散”,输出各条分支,分别用深度优先搜索和广度优先搜索实现。
- (广度优先搜索第一课)迷宫的最短路径 - BFS
- 广度优先搜索迷宫路径算法的实现
- 广度优先搜索--迷宫最短路径--队列
- 使用MFC搜索当前目录下所存在的某种文件,将文件名(路径等)添加到下拉框中,返回文件个数,部分关键代码。。
- 深度优先搜索、广度优先搜索及其生成树
- 从拓扑排序到广度优先搜索到单源最短路径
- 广度优先搜索之最短路径
- 迷宫问题(广度优先搜索,输出最短路径)
- 图的广度优先搜索来求从一个城市到另一个城市的路径及其所经过城市最少